What is the relationship between __getattr__ and getattr?
Asked Answered
D

3

40

I know this code is right:

class A:   
    def __init__(self):
        self.a = 'a'  
    def method(self):   
        print "method print"  

a = A()   
print getattr(a, 'a', 'default')   
print getattr(a, 'b', 'default')  
print getattr(a, 'method', 'default') 
getattr(a, 'method', 'default')()   

And this is wrong:

# will __getattr__ affect the getattr?

class a(object):
    def __getattr__(self,name):
        return 'xxx'

print getattr(a)

This is also wrong:

a={'aa':'aaaa'}
print getattr(a,'aa')

Where should we use __getattr__ and getattr?

Dorsum answered 22/12, 2009 at 7:4 Comment(2)
possible duplicate of Understanding the difference between __getattr__ and __getattribute__Chondro
@Trilarion that is not a proper duplicate for this questionScramble
F
64

Alex's answer was good, but providing you with a sample code since you asked for it :)

class foo:
    def __init__(self):
        self.a = "a"
    def __getattr__(self, attribute):
        return "You asked for %s, but I'm giving you default" % attribute


>>> bar = foo()
>>> bar.a
'a'
>>> bar.b
"You asked for b, but I'm giving you default"
>>> getattr(bar, "a")
'a'
>>> getattr(bar, "b")
"You asked for b, but I'm giving you default"

So in short answer is

You use

__getattr__ to define how to handle attributes that are not found

and

getattr to get the attributes

Farleigh answered 22/12, 2009 at 7:26 Comment(1)
Watch out if you use __getattr__ because it breaks the copy built in module unless you also implement __copy__ and __deepcopy__ for your class. Took me some time to trace this bug... On 2.7 anywaysIntosh
A
40

getattr is a built-in function taking (at least) two arguments: the object from which you're getting the attribute, and the string name of the attribute.

If the string name is a constant, say 'foo', getattr(obj, 'foo') is exactly the same thing as obj.foo.

So, the main use case for the built-in function getattr is when you don't have the attribute name as a constant, but rather as a variable. A second important use case is when you pass it three arguments, rather than just two: in that case, if the attribute is absent from the object, getattr returns the third, "default", argument, rather than raising an exception.

__getattr__ is a special method, defined in a class, that gets invoked when some attribute of an instance of that class is requested, and other normal ways to supply that attribute (via the instance's __dict__, slots, properties, and so on) all failed. You can define it, for example, when you want to delegate otherwise-undefined attribute lookups to other objects.

So your second example is wrong because the builtin getattr can never be called with a single argument.

The third one fails because the dictionary you're trying to "get an attribute" from does not have that attribute -- it has items, which are totally disjoint from attributes of course.

Apparel answered 22/12, 2009 at 7:14 Comment(2)
While your answer is excellent, @Dorsum wanted a code sample because his english is not so good.Farleigh
I'm not sure if this is incorrect or just insufficient: "if the attribute is absent from the object, getattr returns the third, "default", argument, rather than raising an exception". It may not be correct because getattr either raises an exception (in order to catch it) like hasattr, possibly even using hasattr, or it uses another mechanism, but __getattr__ still gets called, even if there's a default argument provided. Either way, getattr does not return the third argument if __getattr__ is present, I believe. The use of __getattr__ seems to block 3 argument getattr.Ovenbird
G
19

__getattr__() is a special method function that you can define. When a member lookup fails, this function will be called.

getattr() is a function you can call to attempt a member lookup. If the lookup succeeds, you get the member (perhaps a method function object, or perhaps a data attribute object). getattr() can also return a default in the case the lookup fails.

If you declare a __getattr__() member function, you can make it succeed sometimes, or you can make it succeed every time.

class A(object):
    def __getattr__(self, name):
        return "I pretend I have an attribute called '%s'" % name

a = A()

print a.foo # prints "I pretend I have an attribute called 'foo'"

Python also has __getattribute__() which is always called on every lookup. It is very dangerous because it can make it impossible to access members normally.

class A(object):
    def __init__(self, value):
        self.v = value
    def __getattribute__(self, name):
        return "I pretend I have an attribute called '%s'" % name

a = A(42)

print a.v # prints "I pretend I have an attribute called 'v'"
print a.__dict__["v"] # prints "I pretend I have an attribute called '__dict__'"

Oops, it is now impossible to access a.v!

Gustation answered 22/12, 2009 at 7:28 Comment(2)
+1 for mentioning getattribute which I guess the question was actually about.Intimacy
Nice and simple explanation of getattribute that had always seemed unclear to me.Oreopithecus

© 2022 - 2024 — McMap. All rights reserved.