在 Python 中创建实例方法对象的不同方式

Different way to create an instance method object in Python

Python 3.x 语言参考描述了两种创建方法对象的方法:

User-defined method objects may be created when getting an attribute of a class (perhaps via an instance of that class), if that attribute is a user-defined function object or a class method object.

When an instance method object is created by retrieving a user-defined function object from a class via one of its instances, its self attribute is the instance, and the method object is said to be bound. The new method’s func attribute is the original function object.

When a user-defined method object is created by retrieving another method object from a class or instance, the behaviour is the same as for a function object, except that the func attribute of the new instance is not the original method object but its func attribute.

When an instance method object is called, the underlying function (func) is called, inserting the class instance (self) in front of the argument list. For instance, when C is a class which contains a definition for a function f(), and x is an instance of C, calling x.f(1) is equivalent to calling C.f(x, 1).

When an instance method object is derived from a class method object, the “class instance” stored in self will actually be the class itself, so that calling either x.f(1) or C.f(1) is equivalent to calling f(C,1) where f is the underlying function.

在不同的方面,它们都有不同的__func____self__值,但是我不是很了解这两种不同的方式,有人可以向我解释一下吗?

Python 语言参考 |标准类型层次结构: https://docs.python.org/3/reference/datamodel.html#the-standard-type-hierarchy

我不是 100% 确定我完全理解您的问题,但查看示例可能会有所帮助。首先,让我们创建一个 class ,它在定义中有一个函数:

>>> class Foo(object):
...   def method(self):
...     pass
... 
>>> f = Foo()

User-defined method objects may be created when getting an attribute of a class (perhaps via an instance of that class), if that attribute is a user-defined function object or a class method object.

好的,所以我们可以通过访问实例上的属性来创建一个方法对象(如果属性是一个函数)。在我们的设置中,f 是 class Foo:

的一个实例
>>> type(f.method)
<class 'method'>

将其与访问 class 上的方法属性进行比较:

>>> type(Foo.method)
<class 'function'>

When an instance method object is created by retrieving a user-defined function object from a class via one of its instances, its __self__ attribute is the instance, and the method object is said to be bound. The new method’s __func__ attribute is the original function object.

这只是告诉我们实例方法上存在哪些属性。让我们来看看:

>>> instance_method = f.method
>>> instance_method.__func__ is Foo.method
True
>>> instance_method.__self__ is f
True

所以我们看到方法对象有一个 __func__ 属性,它只是对实际 Foo.method 函数的引用。它还有一个 __self__ 属性,它是对 实例 .

的引用

When an instance method object is called, the underlying function (func) is called, inserting the class instance (self) in front of the argument list. For instance, when C is a class which contains a definition for a function f(), and x is an instance of C, calling x.f(1) is equivalent to calling C.f(x, 1).

基本上,参考我们上面的例子,这只是说 If:

instance_method = f.method

然后:

instance_method(arg1, arg2)

执行以下操作:

instance_method.__func__(instance_method.__self__, arg1, arg2)

为了完整性和作为@mgilson 提供的出色答案的附录,我想解释原始问题中引用的其余 2 段。

首先让我们创建一个 class 和 classmethod:

>>> class Foo(object):
...   @classmethod
...   def cmethod(cls):
...     pass
... 
>>> f = Foo()

现在是第 3 段:

When a user-defined method object is created by retrieving another method object from a class or instance, the behaviour is the same as for a function object, except that the func attribute of the new instance is not the original method object but its func attribute.

这意味着:

>>> class_method = f.cmethod
>>> class_method.__func__ is Foo.cmethod.__func__
True
>>> class_method.__self__ is Foo
True

请注意 __self__ 是对 Foo class 的引用。最后,最后一段:

When an instance method object is derived from a class method object, the “class instance” stored in self will actually be the class itself, so that calling either x.f(1) or C.f(1) is equivalent to calling f(C,1) where f is the underlying function.

这只是说以下所有内容都是等价的:

>>> f.cmethod(arg1, arg2)
>>> Foo.cmethod(arg1, arg2)
>>> f.cmethod.__func__(Foo, arg1, arg2)
>>> Foo.cmethod.__func__(Foo, arg1, arg2)
>>> f.cmethod.__func__(f.cmethod.__self__, arg1, arg2)
>>> Foo.cmethod.__func__(Foo.cmethod.__self__, arg1, arg2)