我是python的新手,我不太了解__func__python 2.7.
我知道什么时候定义这样的类:
class Foo:
def f(self, arg):
print arg
Run Code Online (Sandbox Code Playgroud)
我可以使用Foo().f('a')或Foo.f(Foo(), 'a')调用此方法.但是,我无法通过此方法调用此方法Foo.f(Foo, 'a').但我意外地发现我可以使用Foo.f.__func__(Foo, 'a')甚至Foo.f.__func__(1, 'a')获得相同的结果.
我打印出的值Foo.f,Foo().f和Foo.f.__func__,它们都是不同的.但是,我在定义中只有一段代码.谁可以帮助解释上面的代码实际上是如何工作的,特别是__func__?我现在真的很困惑.
Mar*_*ers 38
当您访问Foo.f或Foo().f一个方法返回; 它在第一种情况下是未绑定的,在第二种情况下是绑定的.python方法本质上是一个函数的包装器,它还包含对类的引用.绑定时,它还包含对实例的引用.
当你调用一个方法时,它会对传入的第一个参数进行类型检查,以确保它是一个实例(它必须是引用类的实例,或者是该类的子类).当绑定方法时,它将提供第一个参数,在您自己提供的未绑定方法上.
这个方法对象具有__func__属性,它只是对包装函数的引用.通过访问底层函数而不是调用方法,可以删除类型检查,并且可以将任何您想要的内容作为第一个参数传递.函数不关心它们的参数类型,但方法可以.
请注意,在Python 3中,这已经改变了; Foo.f只返回函数,而不是未绑定的方法.Foo().f返回仍然仍然绑定的方法,但是无法再创建未绑定的方法.
在引擎盖下,每个函数对象都有一个__get__方法,这是返回方法对象的东西:
>>> 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>
Run Code Online (Sandbox Code Playgroud)
这是不是最有效的代码路径,那么,Python的3.7增加了一个新的LOAD_METHOD- CALL_METHOD操作码对,替换当前的LOAD_ATTRIBUTE- CALL_FUNCTION精确的操作码对,以避免每次创建一个新的方法的对象.这种优化变换executon路径instance.foo()从type(instance).__dict__['foo'].__get__(instance, type(instance))()与type(instance).__dict__['foo'](instance),因此在该实例"手动"直接传递给函数的对象.这节省了现有微基准测试的大约20%的时间.