What/Where Are the Attributes of a Function Object

What/Where are the attributes of a function object?

As far as I know, srcref is the only attribute typically attached to S3 functions. (S4 functions are a different matter, and I wouldn't recommend messing with their sometimes numerous attributes).

The srcref attribute is used for things like enabling printing of comments included in a function's source code, and (for functions that have been sourced in from a file) for setting breakpoints by line number, using utils::findLineNum() and utils::setBreakpoint().

If you don't want your functions to carry such additional baggage, you can turn off recording of srcref by doing options(keep.source=FALSE). From ?options (which also documents the related keep.source.pkgs option):

‘keep.source’: When ‘TRUE’, the source code for functions (newly
defined or loaded) is stored internally allowing comments to
be kept in the right places. Retrieve the source by printing
or using ‘deparse(fn, control = "useSource")’.

Compare:

options(keep.source=TRUE)
f1 <- function(x) {
## This function is needlessly commented
x
}

options(keep.source=FALSE)
f2 <- function(x) {
## This one is too
x
}

length(attributes(f1))
# [1] 1
f1
# function(x) {
# ## This function is needlessly commented
# x
# }

length(attributes(f2))
# [1] 0
f2
# function (x)
# {
# x
# }

How to see function attributes?

Just like any other object, you can use vars:

def func(a):
return a*a

func.attr = 1

print(vars(func))
# {'attr': 1}

Python function attributes - uses and abuses

I typically use function attributes as storage for annotations. Suppose I want to write, in the style of C# (indicating that a certain method should be part of the web service interface)

class Foo(WebService):
@webmethod
def bar(self, arg1, arg2):
...

then I can define

def webmethod(func):
func.is_webmethod = True
return func

Then, when a webservice call arrives, I look up the method, check whether the underlying function has the is_webmethod attribute (the actual value is irrelevant), and refuse the service if the method is absent or not meant to be called over the web.

Is there a function in Python to list the attributes and methods of a particular object?

You want to look at the dir() function:

>>> li = []
>>> dir(li)
['append', 'count', 'extend', 'index', 'insert',
'pop', 'remove', 'reverse', 'sort']

li is a list, so dir(li) returns a list of all the methods of a list. Note that the returned list contains the names of the methods as strings, not the methods themselves.


Edit in response to comment:

No this will show all inherited methods as well. Consider this example:

test.py:

class Foo:
def foo(): pass

class Bar(Foo):
def bar(): pass

Python interpreter:

>>> from test import Foo, Bar
>>> dir(Foo)
['__doc__', '__module__', 'foo']
>>> dir(Bar)
['__doc__', '__module__', 'bar', 'foo']

You should note that Python's documentation states:

Note: Because dir() is supplied
primarily as a convenience for use at
an interactive prompt
, it tries to
supply an interesting set of names
more than it tries to supply a
rigorously or consistently defined set
of names, and its detailed behavior
may change across releases
. For
example, metaclass attributes are not
in the result list when the argument
is a class.

Therefore it's not safe to use in your code. Use vars() instead. Vars() doesn't include information about the superclasses, you'd have to collect them yourself.


If you're using dir() to find information in an interactive interpreter, consider the use of help().

How can a function access its own attributes?

Solution

Make one of the function's default arguments be a reference to the function itself.

def f(self):
return self.x
f.func_defaults = (f,)

Example usage:

>>> f.x = 17
>>> b = f
>>> del f
>>> b()
17

Explanation

The original poster wanted a solution that does not require a global name lookup. The simple solution

def f():
return f.x

performs a lookup of the global variable f on each call, which does not meet the requirements. If f is deleted, then the function fails. The more complicated inspect proposal fails in the same way.

What we want is to perform early binding and store the bound reference within the object itself. The following is conceptually what we are doing:

def f(self=f):
return self.x

In the above, self is a local variable, so no global lookup is performed. However, we can't write the code as-is, because f is not yet defined when we try to bind the default value of self to it. Instead, we set the default value after f is defined.

Decorator

Here's a simple decorator to do this for you. Note that the self argument must come last, unlike methods, where self comes first. This also means that you must give a default value if any of your other arguments take a default value.

def self_reference(f):
f.func_defaults = f.func_defaults[:-1] + (f,)
return f

@self_reference
def foo(verb, adverb='swiftly', self=None):
return '%s %s %s' % (self.subject, verb, adverb)

Example:

>>> foo.subject = 'Fred'
>>> bar = foo
>>> del foo
>>> bar('runs')
'Fred runs swiftly'

Get all object attributes in Python?

Use the built-in function dir().

Finding what methods a Python object has

For many objects, you can use this code, replacing 'object' with the object you're interested in:

object_methods = [method_name for method_name in dir(object)
if callable(getattr(object, method_name))]

I discovered it at diveintopython.net (now archived), that should provide some further details!

If you get an AttributeError, you can use this instead:

getattr() is intolerant of pandas style Python 3.6 abstract virtual sub-classes. This code does the same as above and ignores exceptions.

import pandas as pd
df = pd.DataFrame([[10, 20, 30], [100, 200, 300]],
columns=['foo', 'bar', 'baz'])
def get_methods(object, spacing=20):
methodList = []
for method_name in dir(object):
try:
if callable(getattr(object, method_name)):
methodList.append(str(method_name))
except Exception:
methodList.append(str(method_name))
processFunc = (lambda s: ' '.join(s.split())) or (lambda s: s)
for method in methodList:
try:
print(str(method.ljust(spacing)) + ' ' +
processFunc(str(getattr(object, method).__doc__)[0:90]))
except Exception:
print(method.ljust(spacing) + ' ' + ' getattr() failed')

get_methods(df['foo'])

Terminology: A user-defined function object attribute?

When you do

class Foo(object):
def meth(self):
pass

you are defining a class Foo with a method meth. However, when this class definition is executed, no method object is created to represent the method. The def statement creates an ordinary function object.

If you then do

Foo.meth

or

Foo().meth

the attribute lookup finds the function object, but the function object is not used as the value of the attribute. Instead, using the descriptor protocol, Python calls the __get__ method of the function object to construct a method object, and that method object is used as the value of the attribute for that lookup. For Foo.meth, the method object is an unbound method object, which behaves like the function you defined, but with an extra type checking of self. For Foo().meth, the method object is a bound method object, which already knows what self is.


This is why Foo().meth() doesn't complain about a missing self argument; you pass 0 arguments to the method object, which then prepends self to the (empty) argument list and passes the arguments on to the underlying function object. If Foo().meth evaluated to the meth function directly, you would have to pass it self explicitly.


In Python 3, Foo.meth doesn't create an unbound method object; the function's __get__ still gets called, but it returns the function directly, since Guido decided unbound method objects weren't useful. Foo().meth still creates a bound method object, though.



Related Topics



Leave a reply



Submit