I\'ve recently read about the getattr() function. The problem is that I still can\'t grasp the idea of its usage. The only thing I understand about getattr()
is
getattr(object, 'x')
is completely equivalent to object.x
.
There are only two cases where getattr
can be useful.
object.x
, because you don't know in advance which attribute you want (it comes from a string). Very useful for meta-programming.object.y
will raise an AttributeError
if there's no y
. But getattr(object, 'y', 5)
will return 5
.Quite frequently when I am creating an XML file from data stored in a class I would frequently receive errors if the attribute didn't exist or was of type None
. In this case, my issue wasn't not knowing what the attribute name was, as stated in your question, but rather was data ever stored in that attribute.
class Pet:
def __init__(self):
self.hair = None
self.color = None
If I used hasattr
to do this, it would return True
even if the attribute value was of type None
and this would cause my ElementTree set
command to fail.
hasattr(temp, 'hair')
>>True
If the attribute value was of type None
, getattr
would also return it which would cause my ElementTree set
command to fail.
c = getattr(temp, 'hair')
type(c)
>> NoneType
I use the following method to take care of these cases now:
def getRealAttr(class_obj, class_attr, default = ''):
temp = getattr(class_obj, class_attr, default)
if temp is None:
temp = default
elif type(temp) != str:
temp = str(temp)
return temp
This is when and how I use getattr
.
Here's a quick and dirty example of how a class could fire different versions of a save method depending on which operating system it's being executed on using getattr()
.
import os
class Log(object):
def __init__(self):
self.os = os.name
def __getattr__(self, name):
""" look for a 'save' attribute, or just
return whatever attribute was specified """
if name == 'save':
try:
# try to dynamically return a save
# method appropriate for the user's system
return getattr(self, self.os)
except:
# bail and try to return
# a default save method
return getattr(self, '_save')
else:
return getattr(self, name)
# each of these methods could have save logic specific to
# the system on which the script is executed
def posix(self): print 'saving on a posix machine'
def nt(self): print 'saving on an nt machine'
def os2(self): print 'saving on an os2 machine'
def ce(self): print 'saving on a ce machine'
def java(self): print 'saving on a java machine'
def riscos(self): print 'saving on a riscos machine'
def _save(self): print 'saving on an unknown operating system'
def which_os(self): print os.name
Now let's use this class in an example:
logger = Log()
# Now you can do one of two things:
save_func = logger.save
# and execute it, or pass it along
# somewhere else as 1st class:
save_func()
# or you can just call it directly:
logger.save()
# other attributes will hit the else
# statement and still work as expected
logger.which_os()
A pretty common use case for getattr
is mapping data to functions.
For instance, in a web framework like Django or Pylons, getattr
makes it straightforward to map a web request's URL to the function that's going to handle it. If you look under the hood of Pylons's routing, for instance, you'll see that (by default, at least) it chops up a request's URL, like:
http://www.example.com/customers/list
into "customers" and "list". Then it searches for a controller class named CustomerController
. Assuming it finds the class, it creates an instance of the class and then uses getattr
to get its list
method. It then calls that method, passing it the request as an argument.
Once you grasp this idea, it becomes really easy to extend the functionality of a web application: just add new methods to the controller classes, and then create links in your pages that use the appropriate URLs for those methods. All of this is made possible by getattr
.
Other than all the amazing answers here, there is a way to use getattr
to save copious lines of code and keeping it snug. This thought came following the dreadful representation of code that sometimes might be a necessity.
Scenario
Suppose your directory structure is as follows:
- superheroes.py
- properties.py
And, you have functions for getting information about Thor
, Iron Man
, Doctor Strange
in superheroes.py
. You very smartly write down the properties of all of them in properties.py
in a compact dict
and then access them.
properties.py
thor = {
'about': 'Asgardian god of thunder',
'weapon': 'Mjolnir',
'powers': ['invulnerability', 'keen senses', 'vortex breath'], # and many more
}
iron_man = {
'about': 'A wealthy American business magnate, playboy, and ingenious scientist',
'weapon': 'Armor',
'powers': ['intellect', 'armor suit', 'interface with wireless connections', 'money'],
}
doctor_strange = {
'about': ' primary protector of Earth against magical and mystical threats',
'weapon': 'Magic',
'powers': ['magic', 'intellect', 'martial arts'],
}
Now, let's say you want to return capabilities of each of them on demand in superheroes.py
. So, there are functions like
from .properties import thor, iron_man, doctor_strange
def get_thor_weapon():
return thor['weapon']
def get_iron_man_bio():
return iron_man['about']
def get_thor_powers():
return thor['powers']
...and more functions returning different values based on the keys and superhero.
With the help of getattr
, you could do something like:
from . import properties
def get_superhero_weapon(hero):
superhero = getattr(properties, hero)
return superhero['weapon']
def get_superhero_powers(hero):
superhero = getattr(properties, hero)
return superhero['powers']
You considerably reduced the number of lines of code, functions and repetition!
Oh and of course, if you have bad names like properties_of_thor
for variables , they can be made and accessed by simply doing
def get_superhero_weapon(hero):
superhero = 'properties_of_{}'.format(hero)
all_properties = getattr(properties, superhero)
return all_properties['weapon']
NOTE: For this particular problem, there can be smarter ways to deal with the situation, but the idea is to give an insight about using getattr
in right places to write cleaner code.
I have tried in Python2.7.17
Some of the fellow folks already answered. However I have tried to call getattr(obj, 'set_value') and this didn't execute the set_value method, So i changed to getattr(obj, 'set_value')() --> This helps to invoke the same.
Example Code:
Example 1:
class GETATT_VERIFY():
name = "siva"
def __init__(self):
print "Ok"
def set_value(self):
self.value = "myself"
print "oooh"
obj = GETATT_VERIFY()
print getattr(GETATT_VERIFY, 'name')
getattr(obj, 'set_value')()
print obj.value