像dict.fromkeys这样的内置类型的函数描述符与普通方法的行为不同

问题描述 投票:2回答:1

为什么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会区分内置类型函数和这样的普通函数?我们也可以这样做吗?我们可以创建一个只绑定到它所属类型的函数吗?

python python-2.7 python-internals python-descriptors
1个回答
1
投票

class_or_type.descriptor总是调用descriptor.__get__(None, class_or_type),这就是为什么你不能从内置的未绑定方法对象获取__get__。在Python 2函数上为method生成的(未绑定的)__get__类型显式实现了__get__,因为Python方法更灵活。所以builtin.descriptorclass.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那样的未绑定方法对象。整个未绑定/绑定方法的区别,其中未绑定的方法对象在调用时限制第一个参数的类型,但未被发现是有用的,因此它被删除。

© www.soinside.com 2019 - 2024. All rights reserved.