What is getattr() exactly and how do I use it?
getattr(object, 'x')
is completely equivalent to object.x
.
There are only two cases where getattr
can be useful.
- you can't write
object.x
, because you don't know in advance which attribute you want (it comes from a string). Very useful for meta-programming. - you want to provide a default value.
object.y
will raise anAttributeError
if there's noy
. Butgetattr(object, 'y', 5)
will return5
.
getattr on class objects
Is this good enough?
import types
class Test(object):
@staticmethod
def foo():
print 'foo'
def bar(self):
print 'bar'
In combination with:
>>>(isinstance(getattr(Test, 'foo'), types.FunctionType),
isinstance(getattr(Test, 'bar'), types.FunctionType))
True, False
You can also use the inspect
module:
>>> inspect.isfunction(Test.foo)
True
>>> inspect.isfunction(Test.bar)
False
With a little additional work you can even distinguish class methods from instance methods and static methods:
import inspect
def get_type(cls, attr):
try:
return [a.kind for a in inspect.classify_class_attrs(cls) if a.name == attr][0]
except IndexError:
return None
class Test(object):
@classmethod
def foo(cls):
print 'foo'
def bar(self):
print 'bar'
@staticmethod
def baz():
print 'baz'
You can use it as:
>>> get_type(Test, 'foo')
'class method'
>>> get_type(Test, 'bar')
'method'
>>> get_type(Test, 'baz')
'static method'
>>> get_type(Test, 'nonexistant')
None
How does one use python's __import__() and getattr() to correctly to instantiate nested classes?
Two ways to do this, suppose you have a string representing attribute access and a nested object:
>>> from types import SimpleNamespace
>>> module = SimpleNamespace(foo=SimpleNamespace(bar=SimpleNamespace(baz='tada!')))
>>> module
namespace(foo=namespace(bar=namespace(baz='tada!')))
The first is to basically parse the string yourself by splitting and using getattr
in a loop (or even, reduce
!):
>>> from functools import reduce
>>> reduce(getattr, "foo.bar.baz".split('.'), module)
'tada!'
Which is just equivalent to:
>>> result = module
>>> for attr in "foo.bar.baz".split("."):
... result = getattr(result, attr)
...
>>> result
'tada!'
Or use the built-in functools.attrgetter
factory function as a one-off:
>>> import operator
>>> operator.attrgetter("foo.bar.baz")(module)
'tada!'
Why use setattr() and getattr() built-ins?
Because you can use a dynamic variable too:
somevar = 'foo'
getattr(x, somevar)
You can't do that with regular attribute access syntax.
Note that getattr()
also takes an optional default value, to be returned if the attribute is missing:
>>> x = object()
>>> getattr(x, 'foo')
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'object' object has no attribute 'foo'
>>> getattr(x, 'foo', 42)
42
Using getattr()
you can pull the attribute name from something else, not a literal:
for attrname in dir(x):
print('x.{} = {!r}'.format(attrname, getattr(x, attrname))
or you can use setattr()
to set dynamic attributes:
for i, value in enumerate(dynamic_values):
setattr(i, 'attribute{}'.format(i), value)
python getattr returns to handler when exactly is handler set to None?
Okay it seems that you use getattr()
to map function calls by string name to a handler function which is a wrapper for the function you are trying to map over.
use one function to getattr for either functions or regular attributes
Solution 1
You can make length
a property
:
class Thing(object):
def __init__(self):
self.legs = 4
@property
def length(self):
return 6
>>> thing = Thing()
>>> thing.legs
4
>>> thing.length
6
If you really want to use your function:
def set_session_attribute(obj, attribute):
return getattr(obj, attribute)
>>> set_session_attribute(thing, 'legs')
4
>>> set_session_attribute(thing, 'length')
6
If you cannot change the source of thing
directly, you can do after importing the class:
class Thing(object):
def __init__(self):
self.legs = 4
def length(self):
return 6
Here:
Thing.length2 = property(Thing.length)
>>> thing = Thing()
>>> thing.length2
6
Solution 2
Alternatively, you can check if the attribute is callable:
class Thing(object):
def __init__(self):
self.legs = 4
def length(self):
return 6
def set_session_attribute(obj, attribute):
attr = getattr(obj, attribute)
if hasattr(attr, '__call__'): # may use `callable()`
return attr()
return attr
>> thing = Thing()
>>> set_session_attribute(thing, 'legs')
4
>>> set_session_attribute(thing, 'length')
6
Use of getattr on a class with data descriptor
getattr(A, 'a')
triggers the descriptor protocol, even on classes, so String.__get__(None, A)
is called.
That returns None
because your String.__get__()
method has no explicit return
statement.
From the Descriptor Howto:
For classes, the machinery is in
type.__getattribute__()
which transformsB.x
intoB.__dict__['x'].__get__(None, B)
.
getattr(A, 'a')
is just a dynamic from of A.a
here, so A.__dict__['x'].__get__(None, A)
is executed, which is why you don't get the same thing as A.__dict__['x']
.
If you expected it to return the descriptor object itself, you'll have to do so explicitly; instance
will be set to None
in that case:
class String(object):
def __get__(self, instance, owner):
if instance is None:
return self
def __set__(self, instance, value):
pass
This is what the property
descriptor object does.
Note that the owner
argument to descriptor.__get__
is optional; if not set you are supposed to use type(instance)
instead.
Related Topics
Make a Dictionary With Duplicate Keys in Python
How to Clear the Interpreter Console
How to Execute a String Containing Python Code in Python
How to Melt a Pandas Dataframe
Wait Until Page Is Loaded With Selenium Webdriver For Python
Flask View Return Error "View Function Did Not Return a Response"
How to Measure Elapsed Time in Python
How to Fix "Attempted Relative Import in Non-Package" Even With _Init_.Py
Convert All Strings in a List to Int
Tkinter: How to Use After Method
Saving an Object (Data Persistence)
What Are the Advantages of Numpy Over Regular Python Lists
How to Check If a List Is Empty
Does Python Have "Private" Variables in Classes