CoderXL's Blog

Back

在学习 Python 时,有没有形成一种观念,那就是 class 内的函数和外面的函数不一样?

通常来说,类中的函数叫作“方法”(method),它第一个参数会写成 self,并且调用时只需要传入后面的参数,不需要传入 self.

更进阶一点时,会遇到 @classmethod 和 @staticmethod 修饰器,经过了这些修饰器的类函数,第一个参数含义不同或者没有特殊含义。

但这究竟是怎么一回事?


尝试下列代码:

class MyClass:
    def myFunc(self):
        pass

obj = MyClass()

print(obj.myFunc)
print(obj.myFunc.__func__)
print(MyClass.myFunc)
print(obj.myFunc.__func__ is MyClass.myFunc)
python

会发现 obj.myFunc 是一个 bound method 对象,而其余两个都是 function 对象,并且其实是同一个 function 对象。

初见端倪?别急


稍微改动代码:

class MyClass:
    def myFunc(self = "no self passed in"):
        print(self)

obj = MyClass()

print(obj)
obj.myFunc()
obj.myFunc.__func__()
MyClass.myFunc()
python

会发现 MyClass.myFunc 得到的函数没有自动传入 self 参数,和普通的函数无异;而 obj.myFunc 得到的函数传入了 self 参数。


再做一个实验:

class MyClass:
    pass

def normalFunc(arg1 = "no arg1 passed in"):
    print(arg1)

MyClass.myFunc = normalFunc

obj = MyClass()

obj.myFunc()
obj.myFunc.__func__()
MyClass.myFunc()
normalFunc()
python

外部定义的普通函数,只要绑定到了类上,就能复刻类函数的行为?! 而且 self 参数也完全可以不叫 self.

这说明类函数的行为并不是由其定义位置决定的,只是由于它绑定在了类上,并且从类的实例上调用了。

那么,为什么从类实例上调用类函数,就会自动传入 self 作为第一个参数呢?


试试:

class MyClass:
    pass

def normalFunc(arg1 = "no arg1 passed in"):
    print(arg1)

MyClass.myFunc = normalFunc

obj = MyClass()

print(obj.myFunc)
print(normalFunc.__get__(obj, MyClass))

obj.myFunc()
normalFunc.__get__(obj, MyClass)()
python

发现 normalFunc.__get__(obj, MyClass) 也可以得到 bound method 对象,并且效果和 obj.myFunc 是一样的,即 self 参数传入了 obj.

终于可以揭开谜底了。实际上,Python 在你每次写下 obj.myFunc 时,都会查询 MyClass 里面是否存在名为 myFunc 的 function 对象,如果存在,就会返回 MyClass.myFunc.__get__(obj, MyClass).

至于为什么要这样做,以及这背后的底层机制,请见 Descriptor.


请注意,每次运行 MyClass.myFunc.__get__(obj, MyClass) 都会动态生成 bound method 对象,每次生成的对象都是不同的,这也解释了这个诡异现象:

class MyClass:
    def myFunc(self):
        pass

obj = MyClass()

print(obj.myFunc is obj.myFunc)
python
False
Python 颠覆认知的冷知识 #3
https://blog.leosrealms.top/blog/miscellaneous/2026-09-25-python-blows-your-mind-3
Author CoderXL
Published on 2026年9月25日
Comment seems to stuck. Try to refresh?✨