我想在使用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)]
答案 0 :(得分:3)
根据上游,这项工作是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
第一部作品;第二个没有。 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):
。