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

function descriptor on builtin types like dict.fromkeys behaves different to a normal method

为什么 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])

由于函数描述符的类型错误而失败...:[=​​24=]

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 函数上为 __get__ 生成的(未绑定)method 类型显式实现了 __get__,因为 Python 方法更加灵活。因此 builtin.descriptorclass.descriptor 都调用 .__get__(),但是 returns 的对象类型不同,对于 Python 方法,对象类型代理属性访问:

通过__dict__访问属性,另一方面,从不调用__get__,所以class_or_type.__dict__['fromkeys']给你原始的描述符对象。

在幕后,像 dict 这样的类型,包括它们的方法,是用 C 代码实现的,不在 Python 代码中,C 是很多对类型更挑剔。您永远不能使用旨在处理 dict 对象的内部实现细节的函数和列表,所以何必呢?

仅此而已;内置类型的方法与Python中实现的函数/方法不同,因此虽然它们大部分工作相同,它们不能使用动态类型,描述符如何工作的实现反映了这一点。

并且因为 Python 函数(包装在方法中或不包装),可以使用任何 Python 类型(如果这样设计的话),未绑定的 method 对象支持 __get__这样你就可以把任何这样的东西粘在另一个东西上 class;通过支持 __get__ 他们支持重新绑定到新的 class.

如果你想用 Python 类型实现同样的事情,你必须将函数对象包装在自定义描述符中,然后实现你自己的 __get__ 行为来限制可接受的行为。


请注意,在 Python 3 中,function.__get__(None, classobject) 只是 returns 函数对象本身,而不是像 Python 2 那样的未绑定方法对象。整个未绑定/绑定方法的区别,其中未绑定方法对象在调用时限制第一个参数的类型,被发现并不是那么有用,所以它被删除了。