为什么dict.fromkeys
的函数描述符的功能与其他普通函数不同。
首先,你不能像这样访问__get__
:dict.fromkeys.__get__
你必须从__dict__
获得它。 (dict.__dict__['fromkeys'].__get__
)
然后它不像任何其他函数那样工作,因为它只会让自己绑定到dict
。
这符合我的预期:
class Thing:
def __init__(self):
self.v = 5
def test(self):
print self.v
class OtherThing:
def __init__(self):
self.v = 6
print Thing.test
Thing.test.__get__(OtherThing())
然而,这会出乎意料:
#unbound method fromkeys
func = dict.__dict__["fromkeys"]
但它的描述与正常的未绑定函数不同,看起来像:<method 'fromkeys' of 'dict' objects>
而不是:<unbound method dict.fromkeys>
这是我的意思
这按预期工作:
func.__get__({})([1,2,3])
但你不能将它绑定到我理解的其他东西它不会起作用,但这通常不会阻止我们:
func.__get__([])([1,2,3])
这会因函数描述符中的类型错误而失败...:
descriptor 'fromkeys' for type 'dict' doesn't apply to type 'list'
为什么python会区分内置类型函数和这样的普通函数?我们也可以这样做吗?我们可以创建一个只绑定到它所属类型的函数吗?
class_or_type.descriptor
总是调用descriptor.__get__(None, class_or_type)
,这就是为什么你不能从内置的未绑定方法对象获取__get__
。在Python 2函数上为method
生成的(未绑定的)__get__
类型显式实现了__get__
,因为Python方法更灵活。所以builtin.descriptor
和class.descriptor
都会调用.__get__()
,但返回的对象类型不同,而对于Python方法,对象类型代理属性访问:
另一方面,通过__dict__
访问属性从不调用__get__
,因此class_or_type.__dict__['fromkeys']
为您提供原始描述符对象。
在引擎盖下,像dict
这样的类型,包括它们的方法,都是用C代码实现的,而不是用Python代码实现的,C对类型更加挑剔。您不能使用专门用于处理带有列表的dict
对象的内部实现细节的函数,那么为什么要这么麻烦?
这真的就是它的全部;内置类型的方法与Python中实现的函数/方法不同,因此虽然它们大多数都是相同的,但是它们不能用于动态类型,并且描述符的工作方式的实现反映了这一点。
因为Python函数(包含在方法中或不包含),可以使用任何Python类型(如果这样设计),未绑定的method
对象支持__get__
,以便您可以获取任何此类对象并将其粘贴到另一个类;通过支持__get__
,他们支持重新绑定到新的班级。
如果你想用Python类型实现相同的功能,你必须将函数对象包装在自定义描述符中,然后实现自己的__get__
行为来限制可接受的内容。
请注意,在Python 3中,function.__get__(None, classobject)
只返回函数对象本身,而不是像Python 2那样的未绑定方法对象。整个未绑定/绑定方法的区别,其中未绑定的方法对象在调用时限制第一个参数的类型,但未被发现是有用的,因此它被删除。