class cls: def method(self,x,y): return x+y # 1. 直接访问类的属性 method print(cls.method) # 2. 实例访问 obj = cls() print(obj.method)
<function cls.method at 0x...>
<bound method cls.method of <__main__.cls object at 0x...>>
关键点:
cls.method 是原始函数对象(function),而 function 类本身实现了描述符协议 __get__,所以函数是非数据描述符。
二、function 的 get 原理(描述符核心)
描述符协议:只要对象实现 __get__ / __set__ / __delete__ 就是描述符。
函数只实现了 __get__,属于非数据描述符。
function.__get__(self_func, instance, owner_class) 参数说明:
1. self_func:函数自身(这里就是 cls.method 这个 function 对象)
2. instance:调用时的实例对象;类直接访问时为 None
3. owner_class:所属类(cls)
两种访问逻辑
1. 类访问:cls.method
等价于:function_obj.__get__(None, cls)
instance=None,__get__ 直接返回原函数本身,所以拿到原生 function。
2. 实例访问:obj.method
等价于:function_obj.__get__(obj, cls)
instance=obj,__get__ 会包装生成一个 bound method(绑定方法),把实例 obj 绑定为第一个参数 self,调用时自动传入。
三、手写极简模拟 function 的 get
直观看懂绑定逻辑:
class MyFunc: def __init__(self, func): self.func = func # 实现描述符 __get__ def __get__(self, instance, owner): if instance is None: # 类访问,返回自身(原生函数) return self else: # 实例访问,返回绑定器,自动塞self def bound_method(*args, **kwargs): return self.func(instance, *args, **kwargs) return bound_method # 测试 class Cls: @MyFunc def method(self, x, y): return x + y print(Cls.method) # 类访问,MyFunc实例(原生函数包装) obj = Cls() print(obj.method(1,2)) # 自动传入self,输出3
. def 定义在类内部,本质是把一个 function 对象赋值给类属性;
2. function 内置 __get__,是标准描述符;
3. 类名.方法名 → 触发 __get__(None, 类) → 返回原始 function;
4. 实例.方法名 → 触发 __get__(实例, 类) → 返回绑定方法 bound method;