I came across this as a bit of a surprise while trying to work out another question.
This seemed extremely odd to me, I thought it was worth asking the question. Why doesn't __getattr__
appear to work with with
?
if I make this object:
class FileHolder(object):
def __init__(self,*args,**kwargs):
self.f= file(*args,**kwargs)
def __getattr__(self,item):
return getattr(self.f,item)
and using it with with
,
>>> a= FileHolder("a","w")
>>> a.write
<built-in method write of file object at 0x018D75F8>
>>> with a as f:
... print f
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: __exit__
>>> a.__exit__
<built-in method __exit__ of file object at 0x018D75F8>
Why does this happen?
>>> object.__exit__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: type object 'object' has no attribute '__exit__'
It definitely isn't inheriting __exit__
Okay, so it's cool that you can use getattr to get methods as well as properties, but how does that help us? Well, this can definitely be useful in keeping your code DRY if you have some common logic surrounding branching method calls.
Python getattr() function. Python getattr() function is used to get the value of an object's attribute and if no attribute of that object is found, default value is returned.
Python getattr() The getattr() method returns the value of the named attribute of an object. If not found, it returns the default value provided to the function.
Python getattr() function is used to access the attribute value of an object and also gives an option of executing the default value in case of unavailability of the key.
The with
statement opcode SETUP_WITH
looks up __exit__
as a "special method lookup", which ignores __getattr__
and __getattribute__
on new-style classes (but not on old-style classes). See this mailing list thread for more information, where they discuss adding the special method lookup semantics to with
(which they eventually do). See also special method lookup for new-style classes for a detailed discussion on why these special methods are looked up in this way.
In particular, special method lookup also bypasses __getattr__
on the type object. So, even though the documentation says the method is looked up as type(mgr).__exit__
, this code doesn't work:
class M(type):
def __getattr__(*args): return lambda: 0
class X(object):
__metaclass__ = M
x = X()
type(x).__exit__ # works, returns a lambda
with x: pass # fails, AttributeError
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With