为什么在Python 3中可以将实例方法作为类方法调用?

Why can instance methods be called as class methods in Python 3?

考虑以下类别:

1
2
3
class Foo(object):
    def bar(self):
        print(self)

在python 2(2.7.13)中,作为类方法调用bar()会引发异常:

1
2
3
4
5
6
7
8
9
>>> Foo.bar('hello')
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got str instance instead)

>>> Foo.bar()
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
TypeError: unbound method bar() must be called with Foo instance as first argument (got nothing instead)

当调用bar()作为实例方法时,在不带参数的情况下调用时,它识别self作为实例。

1
2
3
4
5
6
7
>>> Foo().bar('hello')
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
TypeError: bar() takes exactly 1 argument (2 given)

>>> Foo().bar()
<__main__.Foo object at 0x10a8e1a10>

在python 3(3.6.0)中,当调用bar()作为类方法时,第一个参数被接受为self

1
2
3
4
5
6
7
>>> Foo.bar('hello')
hello

>>> Foo.bar()
 Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
TypeError: bar() missing 1 required positional argument: 'self'

作为实例方法调用bar()的工作方式与在python 2中相同

1
2
3
4
5
6
7
>>> Foo().bar('hello')
Traceback (most recent call last):
  File"<stdin>", line 1, in <module>
TypeError: bar() takes 1 positional argument but 2 were given

>>> Foo().bar()
<__main__.Foo object at 0x104ab34a8>


在python 3上,Foo.bar只是您编写的bar函数。它接受一个参数,这个参数恰好被命名为self,并打印出来。你可以对任何东西调用这个函数,它将打印你传递给它的任何参数。

在python 2上,Foo.bar不是您编写的bar函数。访问Foo.bar时,python生成一个包装bar函数的未绑定方法对象。未绑定方法对象的工作方式主要类似于bar函数,其主要区别在于验证其第一个参数是否是Foo的实例。你可以做到

1
Foo.bar(some_foo_instance)

它与some_foo_instance.bar()类似,但调用Foo的实现,绕过子类中的任何覆盖。不过,你不能做Foo.bar('hello')

python 3删除了未绑定的方法对象。它们不再存在了。这使得语言简单了一点,但它删除了用于执行的验证未绑定方法对象。