我以前从未见过这样的事情。
还有其他事情吗?
>>> class NothingSpecial:
@classmethod
def meth(cls): pass
>>> NothingSpecial.meth
<bound method classobj.meth of <class __main__.NothingSpecial at 0x02C68C70>>
>>> NothingSpecial.__dict__['meth']
<classmethod object at 0x03F15FD0>
>>> getattr(NothingSpecial, 'meth')
<bound method NothingSpecial.meth of <class '__main__.NothingSpecial'>>
>>> object.__getattribute__(NothingSpecial, 'meth')
<classmethod object at 0x03FAFE90>
>>> type.__getattribute__(NothingSpecial, 'meth')
<bound method NothingSpecial.meth of <class '__main__.NothingSpecial'>>
答案 0 :(得分:1)
主要区别在于字典查找没有额外处理,而属性提取包含额外的逻辑(有关所有细节,请参阅我的Descriptor How-To Guide)。
1)调用NothingSpecial.__dict__['meth']
使用方括号运算符调度到dict.__getitem__
执行简单的哈希表查找,或者如果找不到则引发 KeyError 。
2)调用NothingSpecial.meth
使用调度到type.__getattribute__
的点运算符,它执行简单查找,然后是descriptors的特殊情况。如果查找失败,则会引发 AttributeError 。
通常,描述符是具有“绑定”的对象属性 行为“,其属性访问权已被方法覆盖 在描述符协议中:__ get __(),__ set __()和/或__delete __()。如果 任何这些方法都是为一个对象定义的,据说是一个 描述符。
属性访问的默认行为是获取,设置或删除 来自对象字典的属性。例如,a.x有一个 查找链以.__ dict __ ['x']开头,然后 键入(a).__ dict __ ['x'],并继续通过基类 (a)不包括元类。
但是,如果查找的值是定义其中一个的对象 描述符方法,然后Python可以覆盖默认行为和 改为调用描述符方法。这种情况发生在哪里 优先级链取决于定义的描述符方法和 他们是如何被称为
希望您发现所有这些都有帮助。您正在进行的探索是了解Python的好方法: - )
P.S。您可能也喜欢阅读Python 2.2 entry for descriptors中的原始Whatsnew,或者查看Guido van Rossum最初提出这个想法的PEP 252。
答案 1 :(得分:0)
object.__getattribute__(NothingSpecial, 'meth')
和
NothingSpecial.__dict__['meth']
在这种情况下,返回相同的对象。您可以通过执行以下操作快速检查:
NothingSpecial.__dict__['meth'] is object.__getattribute__(NothingSpecial, 'meth')
$True
它们都指向相同的descriptor object
另一方面:
object.__getattribute__(NothingSpecial, 'meth') is getattr(NothingSpecial, 'meth')
$False
基本上,他们不是同一个对象和同一类型的对象:
type(object.__getattribute__(NothingSpecial, 'meth'))
$<class 'classmethod'>
type(getattr(NothingSpecial, 'meth'))
$<class 'method'>
答案 2 :(得分:0)
所以答案是getattr
会自动调用对象的__get__
方法(如果有),而object.__getattribute__
和对象__dict__
查找不会。以下功能证明:
class Nothing:
@classmethod
def a(cls):
return cls()
@staticmethod
def b():
return 'b'
def c(self):
return 'c'
def gitter(obj, name):
value = object.__getattribute__(obj, name)
if hasattr(value, '__get__'):
if isclass(obj):
instance, cls = None, obj
else:
instance, cls = obj, type(obj)
return value.__get__(instance, cls)
return value
>>> gitter(Nothing, 'a')()
<__main__.Nothing object at 0x03E97930>
>>> gitter(Nothing, 'b')()
'b'
>>> gitter(Nothing(), 'c')()
'c'
但是,gitter(Nothing(), 'b')
目前无法正常工作,因为它未检测到objtype
默认值为None
,但这已足够。