直接赋值函数到类属性不行,因为Python不会自动将其绑定为实例方法,调用时缺少self参数;需用types.MethodType手动绑定或通过setattr添加到类对象并确保函数含self参数。

直接赋值函数到类属性为什么不行
把一个普通函数直接赋给类的属性,比如 MyClass.new_method = my_func,看起来像加了方法,但实际调用时会报 TypeError: missing 1 required positional argument: 'self'。这是因为 Python 不会自动把函数绑定为实例方法——它只是个“裸函数”,没绑定 self,也没进类的 MRO 查找链。
用 types.MethodType 绑定实例方法
要让函数在实例上调用时能接收 self,得用 types.MethodType 手动绑定。这是最常用、最可控的方式:
import types
<p>def say_hello(self):
return f"Hello from {self.name}"</p><p>class Person:
def <strong>init</strong>(self, name):
self.name = name</p><p>p = Person("Alice")
p.say_hello = types.MethodType(say_hello, p)
print(p.say_hello()) # Hello from Alice
- 只对当前实例生效,不影响其他实例或类本身
- 绑定后的方法可访问实例属性(
self.name),也能调用其他实例方法 - 不能通过类名调用(
Person.say_hello()会报错),因为没进类字典
用 setattr 动态添加类方法或静态方法
如果想让所有实例共享新方法,就得加到类对象上,而不是实例上。这时要注意函数类型:
- 加为普通实例方法:需用
setattr(MyClass, 'method_name', func),但func必须显式带self参数,且不加装饰器 - 加为类方法:先用
@classmethod装饰函数,再setattr - 加为静态方法:先用
@staticmethod装饰,再setattr
错误示范:setattr(MyClass, 'f', lambda x: x) —— 这个 lambda 没 self,实例调用会出错;正确写法是 setattr(MyClass, 'f', lambda self: "ok")。
立即学习“Python免费学习笔记(深入)”;
__get__ 手动触发描述符协议(高级但易错)
Python 方法本质是实现了 __get__ 的非数据描述符。你可以手动调用它来模拟绑定:
def greet(self):
return "Hi!"
<h1>等价于 p.greet = types.MethodType(greet, p)</h1><p>bound = greet.<strong>get</strong>(p, Person)
print(bound()) # Hi!
这和 types.MethodType 底层一致,但更底层、更难读。除非你在写框架或调试描述符行为,否则没必要绕开 types.MethodType。
真正容易被忽略的是:动态添加的方法不会出现在 help() 或 IDE 自动补全里,也不会被 inspect.getmembers() 默认捕获(除非你显式传入 predicate=inspect.isfunction 并检查类字典)。调试时别只盯着 dir(instance),得查 instance.__class__.__dict__ 或 type(instance).__dict__。


















