首页 新闻 会员 周边

万物皆继承自 object,而 object 提供了 __getattribute__ 作为 . 运算符的默认实现

0
[已关闭问题] 关闭于 2026-07-15 16:12

```python

class Person: pass p = Person()

print('__getattribute__' in p.__dict__) # False

print('__getattribute__' in dir(p)) # True

print(p.__getattribute__ is object.__getattribute__) # True (或者 Person.__getattribute__)

```

*Tesla*的主页 *Tesla* | 老鸟四级 | 园豆:2040
提问于:2026-07-15 16:07
< >
分享
所有回答(1)
0

因为在 Python 中,点号 . 本身就是一个运算符(称为“属性访问运算符”),重写这些魔术方法,本质上就是重新定义了 . 运算符在自定义对象上的行为。在大多数编程语言中,我们通常认为 +-*== 才是运算符。但在 Python 的底层设计中,点号 .(属性访问)和中括号 [](索引/键值访问)同样被视为运算符。

  • 当你写 a + b 时,Python 底层调用的是 a.__add__(b)
  • 当你写 p["name"] 时,Python 底层调用的是 p.__getitem__("name")
  • 当你写 p.name 时,Python 底层调用的是 p.__getattribute__("name")(如果找不到,再调用 p.__getattr__("name"))。
  • “运算符重载”的广义定义是:让已有的运算符对自定义类的对象产生特定的行为。 既然 . 是运算符,那么通过实现 __getattr__ 等方法来改变 . 的默认行为,自然也就属于“运算符重载”的范畴

你执行 dir(p) 时,dir() 函数并不是只盯着 p 自己看,它会顺藤摸瓜地把 p 的整个“家族族谱”都翻一遍:

  1. 先看 p 自己身上有什么(实例属性)。
  2. 再看 p 的父亲 person 类身上有什么(类属性)。
  3. 最后看 p 的老祖宗 object 类身上有什么。

因为老祖宗 object 类里面定义了 __getattribute__,所以 dir() 在查阅族谱时看到了它,并把它列在了最终的清单里。

 

class person(): pass
p = person()
p.name = 'abc'

Python 所有的类都默认继承自 objectobject 里面已经写好了一个默认的 __setattr__ 方法。这个方法的作用就是简单粗暴地把 'name': 'abc' 塞进对象的 __dict__(属性字典)里。因为你没有去“改变”或“重新定义”这个默认行为,只是顺其自然地使用了它,所以这绝对不叫重载。重载的前提是:你必须自己写代码,去覆盖(Override)或改变原有的默认行为。如果你想把 p.name = 'abc' 变成重载,你必须在类里面显式地定义 __setattr__ 方法:

class person():
# 自己定义了 __setattr__,这才是重载!
      def __setattr__(self, key, value):
                print(f"【拦截成功】有人试图给 {key} 赋值为 {value}!")

             # 增加一点自定义逻辑,比如把名字全变成大写
                if key == 'name':
                   value = value.upper()

            # 最后还是要调用父类的默认方法把值存起来,否则属性存不进去
                super().__setattr__(key, value)

p = person()
p.name = 'abc'
# 输出: 【拦截成功】有人试图给 name 赋值为 abc!

print(p.name)
# 输出: ABC (因为我们在重载方法里把它变成大写了)

  • 没写 __setattr__:Python 用默认方式默默把值存了。(不是重载)
  • 写了 __setattr__:你接管了 =. 组合而成的赋值操作,加入了你自己的逻辑(比如打印日志、转大写、类型检查等),这就叫运算符重载。(是重载)

 

*Tesla* | 园豆:2040 (老鸟四级) | 2026-07-15 16:12
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册