__getattr__不适用于__enter __ - > AttributeError

pha*_*t0m 5 python

我想with在一个__getattr__用于重定向调用的对象上使用.
然而,这似乎不适用于该方法__enter__

请考虑以下简化代码重现错误:

class EnterTest(object):
    def myenter(self):
        pass
    def __exit__(self, type, value, traceback):
        pass

    def __getattr__(self, name):
        if name == '__enter__':
            return self.myenter

enter_obj = EnterTest()
print getattr(enter_obj, '__enter__')

with enter_obj:
    pass
Run Code Online (Sandbox Code Playgroud)

输出:

<bound method EnterTest.myenter of <__main__.EnterTest object at 0x00000000021432E8>>
Traceback (most recent call last):
  File "test.py", line 14, in <module>
    with enter_obj:
AttributeError: __enter__
Run Code Online (Sandbox Code Playgroud)

为什么它不回落到__getattr__因为__enter__没有在对象上存在吗?

当然,如果我只是创建一个__enter__方法并从那里重定向,我可以使它工作,但我想知道为什么它不起作用.

我的python版本如下:

C:\Python27\python27.exe 2.7 (r27:82525, Jul  4 2010, 07:43:08) [MSC v.1500 64 bit (AMD64)]
Run Code Online (Sandbox Code Playgroud)

Gle*_*ard 5

据上游称,这项工作是 2.6 中的一个错误,已在 2.7 中“修复”。简而言之,类似的方法__enter__是在类上查找的,而不是在对象上查找的。

这种晦涩行为的文档位于http://docs.python.org/reference/datamodel#specialnames : x[i] is roughly equivalent to ... type(x).__getitem__(x, i) for new-style classes

您可以使用其他特殊方法来查看此行为:

class foo(object):
    def __iadd__(self, i):
        print i
a = foo()
a += 1

class foo2(object):
    def __getattr__(self, key):
        print key
        raise AttributeError
b = foo2()
b += 1

class foo3(object):
    pass
def func(self, i):
    print i
c = foo3()
c.__iadd__ = func
c += 1
Run Code Online (Sandbox Code Playgroud)

第一个作品;后两个则不然。Python 2.6 不符合__enter__和 的这种行为__exit__,但 2.7 符合。 http://bugs.python.org/issue9259

也就是说,这些方法无法像任何其他属性一样动态处理,这是令人痛苦的不一致。__getattribute__同样,您不能像使用任何其他方法那样检测对这些方法的访问。我找不到任何内在的设计逻辑。Python 通常非常一致,这是一个相当令人不快的缺点。