Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't __getattr__ work with __exit__?

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?

EDIT

>>> 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__

like image 757
GP89 Avatar asked Sep 28 '12 02:09

GP89


People also ask

Does Getattr work with methods?

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.

What does __ Getattr __ do in Python?

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.

Does Getattr return methods?

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.

What is the point of Getattr?

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.


1 Answers

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
like image 106
nneonneo Avatar answered Sep 24 '22 22:09

nneonneo