2

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

4

1 回答 1

1

class_or_type.descriptor总是调用descriptor.__get__(None, class_or_type),这就是为什么你不能__get__内置的未绑定方法对象中获取。为Python 2 函数生成的(未绑定)method类型显式实现,因为 Python 方法更加灵活。所以两者都调用,但是返回的对象类型不同,对于 Python 方法,对象类型代理属性访问:__get____get__builtin.descriptorclass.descriptor.__get__()

__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 那样的未绑定方法对象。整个未绑定/绑定方法的区别,其中未绑定的方法对象在调用时限制了第一个参数的类型,并没有被发现很有用,所以它被删除了。

于 2018-09-02T20:20:32.093 回答