# 注意外部函数上加了self参数
def func(self, age): #这里需要加参数吗
print(age)
class cls:
pass
>>> c = cls
>>> import types
>>> c.printage = types.MethodType(func, c)
>>> c.printage(22)
22
要的
是因为你给 类对象本身 绑了一个方法,而 MethodType 的第二个参数就是“把这个函数绑定到谁身上”。
因此 外层函数必须多一个 self 形参,否则运行时会少一个位置参数而报错。
关键点:
types.MethodType(func, obj)
把 func 变成 obj 的 bound-method。
obj 会作为 第一个实参 自动传给 func,所以 func 的签名必须留第一个形参(习惯叫 self 或 cls)。
def func(self, age): # ← 必须多一个 self
print(age)
c.printage = types.MethodType(func, c)
c.printage(22) # self=c 已经自动传入,只剩 age=22
若把 func 写成 def func(age):,调用时会报
TypeError: func() takes 1 positional argument but 2 were given。
所以:
给 实例 绑定 → 用 self
给 类 绑定 → 用 cls 或仍叫 self 均可,但必须多一个形参
确实很像
types.MethodType(func, cls) 绑定目标 某个现有函数对象,需要 手动 cls.method(),返回类型 普通函数 → bound-method
@classmethod 类体里定义的方法 直接 cls.method() ,method_descriptor → bound-method,@classmethod 会把函数包装成 classmethod 对象
结论:
MethodType 是 运行时手动绑定;@classmethod 是 声明期语法糖,二者效果类似,但来源和用途不同。
Foo.cls_method = types.MethodType(func, Foo)
Foo.cls_method(10) # <class 'main.Foo'> 10
f = Foo()
f.inst_method = types.MethodType(func, f)
f.inst_method(20) # <main.Foo object at 0x...> 20
Foo.cls_method(30) # 仍可用