当你访问 s.pro 时,Python 调用 property 的 get 。
● property 的 get 内部会去查找之前存好的 _fget ,然后执行它。,这个应该是property类的内部实现吧,而我的Descriptor没有这种实现,所以就是直接调用__get__,__set__,__del__
我们可以把这两者的区别总结为:“硬编码逻辑” vs “动态存储逻辑”。
property 的内部实现(动态存储)
正如你所推测的, property 本质上就是一个预先写好的、功能强大的描述符类。它的内部源码逻辑大致如下(伪代码):
class property:
def __init__(self, fget=None, fset=None, fdel=None):
# 1. 【关键】它把传入的方法保存到了自己的实例变量中
self.fget = fget
self.fset = fset
self.fdel = fdel
def __get__(self, obj, objtype=None):
if obj is None:
return self
# 2. 【执行】调用时,它去取之前存好的 fget 并运行
if self.fget is None:
raise AttributeError("unreadable attribute")
return self.fget(obj)
def __set__(self, obj, value):
# 3. 【执行】调用时,它去取之前存好的 fset 并运行
if self.fset is None:
raise AttributeError("can't set attribute")
self.fset(obj, value)
结论: property 的 get 方法本身不包含业务逻辑,它只是一个 “调度器”。它负责去查找你在创建对象时传进去的那个函数( getName ),然后替你去执行它。
你的 Descriptor 的实现(硬编码)
再看你写的 Descriptor 类:
class Descriptor():
# 没有 __init__,所以无法接收外部参数
def __get__(self, instance, owner):
print("sssssssssss") # 逻辑是写死在这里的
结论: 你的 Descriptor 的 get 方法既是 “调度器” 也是 “执行者”。因为你在定义类的时候就把 print("...") 写死了,而且没有通过 init 接收外部函数来替换这个行为,所以无论你怎么用,它永远只打印那串字符。
● 相通点: 它们都是描述符,都会拦截属性的访问( t.de 或 s.pro )。
● 不同点:
● property :是一个通用的容器。它通过 init 接收函数,在 get 中动态调用这些函数。
● 你的 Descriptor :是一个特定的工具。它的行为在定义类的时候就已经静态固定了(写死在方法体里),除非你修改类的源代码,否则它的行为不会变。
同归(底层机制一致)
无论怎么写,当 Python 解释器遇到 t.de 或 s.pro 时,它只认一条规则:
“这个属性是不是描述符?如果是,就调用它的 get 方法。”