【问题标题】:function descriptor on builtin types like dict.fromkeys behaves different to a normal method像 dict.fromkeys 这样的内置类型的函数描述符的行为与普通方法不同
【发布时间】:2019-02-07 23:21:17
【问题描述】:

为什么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】:

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

    【讨论】:

    • 所以builtin-unbound-methods(如果你可以这样称呼他们)没有__get__,而从__dict__获取未绑定方法是__get__的一层吗?跨度>
    • 如果你要实现一个python解释器,你会尝试模仿这种行为,还是希望内置的东西和你用python写的东西一样。求朋友:P
    • @albertjan:但那些对象不支持绑定到任何其他类型。他们对自己需要的东西比 Python 函数要挑剔得多。
    • @albertjan:那种活力水平不值得支持,所以 Python 解释器不支持。
    • @albertjan: 你想象the dict.fromkeys() implementation 在绑定到一个列表时会做什么?在这种情况下,我链接到的 C 代码将如何工作?它恰好已经考虑了子类(这就是 PyDict_CheckExact 调用的目的),但是在面对任意类型时使所有 C 方法实现更加灵活是很多工作,对于极少数可能的情况来说是不值得的你想把方法放在另一个类上
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-11-12
    • 1970-01-01
    • 1970-01-01
    • 2023-04-06
    • 2015-07-02
    • 2010-12-24
    • 1970-01-01
    相关资源
    最近更新 更多