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, sodir(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
Using Filtered Datatables in Shiny
Insert Images Using Knitr::Include_Graphics in a for Loop
R, Deep VS. Shallow Copies, Pass by Reference
How to Collapse Sidebarpanel in Shiny App
Rjava Is Not Picking Up the Correct Java Version
A Way to Access Google Streetview from R
Rcharts with Highcharts as Shiny Application
Using Predict to Find Values of Non-Linear Model
Convert String Date to R Date Fast for All Dates
Left_Join Two Data Frames and Overwrite
How to Ddply() Without Sorting
Function Commenting Conventions in R
R: Serialize Objects to Text File and Back Again
Questions About Set.Seed() in R