请注意以下事项:
>>> dict.__getitem__ # it's a 'method'
<method '__getitem__' of 'dict' objects>
>>> dict.__setitem__ # it's a 'slot wrapper'
<slot wrapper '__setitem__' of 'dict' objects>
>>> id(dict.__dict__['__getitem__']) == id(dict.__getitem__) # no bounding here
True
>>> id(dict.__dict__['__setitem__']) == id(dict.__setitem__) # or here either
True
>>> d = {}
>>> dict.__setitem__(d, 1, 2) # can be called directly (since not bound)
>>> dict.__getitem__(d, 1) # same with this
2
现在我们可以包装它们(__getattr__
即使没有它也可以工作):
class Foo1(dict):
def __getattr__(self, key): return self[key]
def __setattr__(self, key, value): self[key] = value
class Foo2(dict):
"""
It seems, 'slot wrappers' are not bound when present in the __dict__
of a class and retrieved from it via instance (or class either).
But 'methods' are, hence simple assignment works with __setitem__
in your original example.
"""
__setattr__ = lambda *args: dict.__setitem__(*args)
__getattr__ = lambda *args: dict.__getitem__(*args) # for uniformity, or
#__getattr__ = dict.__getitem__ # this way, i.e. directly
o1 = Foo1()
o1.x = 42
print(o1, o1.x)
o2 = Foo2()
o2.x = 42
print(o2, o2.x)
这使:
>>>
({'x': 42}, 42)
({'x': 42}, 42)
有问题的行为背后的机制(可能,我不是专家)在 Python 的“干净”子集之外(如“Learning Python”或“Python in a nutshell”等详尽书籍中所述,并且在 python 中有些松散地指定。 org) 并且属于由实现“按原样”记录的语言部分(并且受到(相当)频繁的更改)。