__getattr__不适用于__enter__ - > AttributeError的

时间:2010-11-10 15:33:21

标签: 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

输出:

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

为什么它不会回归__getattr__,因为对象上不存在__enter__

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

我的python版本如下:

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

2 个答案:

答案 0 :(得分:3)

根据上游,这项工作是2.6中的一个错误,在2.7中被“修复”。简短的回答是类__enter__之类的方法在类上查找,而不是在对象上查找。

此隐晦行为的文档位于http://docs.python.org/reference/datamodel#specialnamesx[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

第一部作品;第二个没有。 Python 2.6不符合__enter____exit__的这种行为,但2.7确实如此。 http://bugs.python.org/issue9259

也就是说,这些方法不能像任何其他属性那样动态处理,这是非常不一致的。同样,您无法使用__getattribute__来访问这些方法,就像您可以使用任何其他方法一样。我找不到任何内在的设计逻辑。 Python通常非常一致,这是一个相当不愉快的瑕疵。

答案 1 :(得分:0)

你使用的是哪个版本的python?这似乎是一个老bug。看看this。您的代码适用于Python 2.5.1 (r251:54863, Feb 6 2009, 19:02:12),其中包含固定def __exit__(self, *args):