the next is my code:
class foo:
def __init__(self):
self.a = "a"
def __getattr__(self,x,defalut):
if x in self:
return x
else:return defalut
a=foo()
print getattr(a,'b','sss')
i know the __getattr__
must be 2 argument,but i want to get a default attribute if the attribute is no being.
how can i get it, thanks
and
i found if defined __setattr__
,my next code is also can't run
class foo:
def __init__(self):
self.a={}
def __setattr__(self,name,value):
self.a[name]=value
a=foo()#error ,why
hi alex, i changed your example:
class foo(object):
def __init__(self):
self.a = {'a': 'boh'}
def __getattr__(self, x):
if x in self.a:
return self.a[x]
raise AttributeError
a=foo()
print getattr(a,'a','sss')
it print {'a': 'boh'},not 'boh' i think it will print self.a not self.a['a'], This is obviously not want to see
why ,and Is there any way to avoid it
You are confusing the getattr
built-in function, which retrieves some attribute binding of an object dynamically (by name), at runtime, and the __getattr__
method, which is invoked when you access some missing attribute of an object.
You can't ask
if x in self:
from within __getattr__
, because the in
operator will cause __getattr__
to be invoked, leading to infinite recursion.
If you simply want to have undefined attributes all be defined as some value, then
def __getattr__(self, ignored):
return "Bob Dobbs"
Your problem number one: you're defining an old-style class (we know you're on Python 2.something, even though you don't tell us, because you're using print
as a keyword;-). In Python 2:
class foo:
means you're defining an old-style, aka legacy, class, whose behavior can be rather quirky at times. Never do that -- there's no good reason! The old-style classes exist only for compatibility with old legacy code that relies on their quirks (and were finally abolished in Python 3). Use new style classes instead:
class foo(object):
and then the check if x in self:
will not cause a recursive __getattr__
call. It will however cause a failure anyway, because your class does not define a __contains__
method and therefore you cannot check if x
is contained in an instance of that class.
If what you're trying to do is whether x
is defined in the instance dict of self
, don't bother: __getattr__
doesn't even get called in that case -- it's only called when the attribute is not otherwise found in self
.
To support three-arguments calls to the getattr
built-in, just raise AttributeError
in your __getattr__
method if necessary (just as would happen if you had no __getattr__
method at all), and the built-in will do its job (it's the built-in 's job to intercept such cases and return the default if provided). That's the reason one never ever calls special methods such as __getattr__
directly but rather uses built-ins and operators which internally call them -- the built-ins and operators provide substantial added value.
So to give an example which makes somewhat sense:
class foo(object):
def __init__(self):
self.blah = {'a': 'boh'}
def __getattr__(self, x):
if x in self.blah:
return self.blah[x]
raise AttributeError
a=foo()
print getattr(a,'b','sss')
This prints sss
, as desired.
If you add a __setattr__
method, that one intercepts every attempt to set attributes on self
-- including self.blah =
whatever. So -- when you need to bypass the very __setattr__
you're defining -- you must use a different approach. For example:
class foo(object):
def __init__(self):
self.__dict__['blah'] = {}
def __setattr__(self, name, value):
self.blah[name] = value
def __getattr__(self, x):
if x in self.blah:
return self.blah[x]
raise AttributeError
a=foo()
print getattr(a,'b','sss')
This also prints sss
. Instead of
self.__dict__['blah'] = {}
you could also use
object.__setattr__(self, 'blah', {})
Such "upcalls to the superclass's implementation" (which you could also obtain via the super
built-in) are one of the rare exceptions to the rules "don't call special methods directly, call the built-in or use the operator instead" -- here, you want to specifically bypass the normal behavior, so the explicit special-method call is a possibility.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.