python - 使用 __func__ 调用实例方法

标签 python

我是python新手,对python 2.7中的__func__不太了解。

我知道当我这样定义一个类时:

class Foo:
    def f(self, arg):
        print arg

我可以使用 Foo().f('a')Foo.f(Foo(), 'a') 来调用这个方法。但是,我不能通过 Foo.f(Foo, 'a') 调用此方法。但是我偶然发现我可以使用 Foo.f.__func__(Foo, 'a') 甚至 Foo.f.__func__(1, 'a') 来获取同样的结果。

我打印出Foo.fFoo().fFoo.f.__func__的值,都是不同的。但是,我只有一段代码在定义中。谁能帮忙解释一下上面的代码是如何工作的,尤其是 __func__?我现在真的很困惑。

最佳答案

当您访问 Foo.fFoo().f 时,会返回一个 method;在第一种情况下它是未绑定(bind)的,在第二种情况下是绑定(bind)的。 python方法本质上是一个函数的包装器,该函数还包含对其作为方法的类的引用。绑定(bind)时,它还保存对实例的引用。

当您调用一个方法时,它会对传入的第一个参数进行类型检查,以确保它是一个实例(它必须是被引用类的实例,或者该类的子类)。当方法被绑定(bind)时,它会在你自己提供的未绑定(bind)方法上提供第一个参数。

正是这个方法对象具有 __func__ 属性,它只是对包装函数的引用。通过访问底层函数而不是调用方法,您可以删除类型检查,并且您可以传入任何您想要的作为第一个参数。函数不关心参数类型,但方法关心。

请注意,在 Python 3 中,这已经改变; Foo.f 只是返回函数,而不是未绑定(bind)的方法。 Foo().f 返回一个仍然绑定(bind)的方法,但是没有办法再创建一个未绑定(bind)的方法了。

在底层,每个函数对象都有一个 __get__ method ,这是返回方法对象的内容:

>>> class Foo(object):
...     def f(self): pass
... 
>>> Foo.f
<unbound method Foo.f>
>>> Foo().f
<bound method Foo.f of <__main__.Foo object at 0x11046bc10>>
>>> Foo.__dict__['f']
<function f at 0x110450230>
>>> Foo.f.__func__
<function f at 0x110450230>
>>> Foo.f.__func__.__get__(Foo(), Foo)
<bound method Foo.f of <__main__.Foo object at 0x11046bc50>>
>>> Foo.f.__func__.__get__(None, Foo)
<unbound method Foo.f>

这不是最有效的代码路径,因此,Python 3.7 添加了一个新的 LOAD_METHOD - CALL_METHOD 操作码对来替换当前的 LOAD_ATTRIBUTE - CALL_FUNCTION 操作码对精确避免每次创建新的方法对象。此优化将 instance.foo() 的执行路径从 type(instance).__dict__['foo'].__get__(instance, type(instance))()使用 type(instance).__dict__['foo'](instance),因此“手动”将实例直接传递给函数对象。这在现有微基准测试上节省了大约 20% 的时间。

关于python - 使用 __func__ 调用实例方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12935241/

相关文章:

python - PIL海报化-修复绿色像素

python - 为什么 Fore.BLUE 使文本以随机字符开头而不是使文本为蓝色?

python - 根据您自己在 python 中的值对字符串进行排序

python - 如何将变量从 View 传递到 Django 中的 base.html?

java - 使用 Java 从 Python GAE 数据存储访问数据

python - 实现一个带约束的 python 列表

python - 在WSGI中,发送响应而不返回

python - 如何压缩Python字典以保存到mysql中

python - Django ORM - 将此自连接查询转换为 ORM

python - 在 Windows 中为 Python 2.6.6 安装 Zbar