鱼C论坛

 找回密码
 立即注册
查看: 41|回复: 5

[已解决]__getattribute__魔法方法问题

[复制链接]
发表于 昨天 15:31 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x


添加了class C的__getattribute__方法,执行代码后why被打印了三次
代码如下:


  1. <div>>>> class C:

  2. <div>...     def __init__(self,name,age):
  3. ...         self.name = name
  4. ...         self.__age = age
  5. ...     def __getattribute__(self, attrname):
  6. ...         print("why")
  7. ...         return super().__getattribute__(attrname)
  8. ...     def __getattr__(self,attrname):
  9. ...         if attrname == "lol":
  10. ...             print("lol")
  11. ...         else:
  12. ...             raise AttributeError(attrname)
  13. ...
  14. ...         
  15. >>> c = C("yzh",16)
  16. >>> c.x
  17. why
  18. Traceback (most recent call last):
  19.   File "<pyshell#3>", line 1, in <module>
  20.     c.x
  21.   File "<pyshell#1>", line 12, in __getattr__
  22.     raise AttributeError(attrname)
  23. why
  24. why
  25. AttributeError: x</div></div>
复制代码


我以为是idle的问题,于是又到pycharm的控制台执行,结果打印的why更多了

   

  1. <div>   
  2. class C:
  3.     def __init__(self, name, age):
  4.         self.name = name
  5.         self.__age = age
  6.     def __getattribute__(self, attrname):
  7.         print("why")
  8.         return super().__getattribute__(attrname)
  9.     def __getattr__(self, attrname):
  10.         if attrname == "lol":
  11.             print("lol")
  12.         else:
  13.             raise AttributeError(attrname)
  14. c = C("yzh",16)
  15. why
  16. why
  17. why
  18. why
  19. why
  20. why
  21. why
  22. why
  23. why
  24. why
  25. why
  26. why
  27. why
  28. why
  29. why
  30. why
  31. why
  32. why
  33. why
  34. why
  35. why</div>
复制代码
并且是在刚实例化这个类的时候就打印了,有大佬能解答一下是什么问题吗?版本是python3.14.0


最佳答案
昨天 15:33
你好!我来解释一下为什么 __getattribute__ 方法会导致 "why" 被多次打印。

首先,__getattribute__ 方法在每次访问对象的任何属性时都会被调用(包括内部属性)。你的代码中,这个方法被重写为每次调用时都打印 "why",然后通过 super().__getattribute__(attrname) 返回属性值。

在 IDLE 中执行 c.x 时,"why" 被打印三次的原因如下:
  • 第一次打印:直接访问 c.x 触发 __getattribute__("x")
  • 第二次和第三次打印:当属性 x 不存在时,Python 会调用 __getattr__("x"),但在这个过程中,异常处理或 Traceback 显示可能会额外访问对象的其他属性(例如 __class____dict__),从而再次触发 __getattribute__


在 PyCharm 控制台中,实例化对象时打印更多次 "why",是因为控制台环境通常会立即调用对象的 __repr__ 方法(用于显示对象),而默认的 __repr__ 会访问多个基础属性(如 __class____dict__ 等),每次访问都会触发 __getattribute__

简单来说,任何属性访问(包括 Python 内部操作)都会导致 "why" 被打印。如果你不希望这样,可以调整 __getattribute__ 的实现,例如避免在访问特定属性时打印。

示例代码修改(避免无限递归):

  1. class C:
  2.     def __init__(self, name, age):
  3.         self.name = name
  4.         self.__age = age
  5.     def __getattribute__(self, attrname):
  6.         # 只在访问非特殊属性时打印
  7.         if not attrname.startswith('__'):
  8.             print("why")
  9.         return super().__getattribute__(attrname)
  10.     def __getattr__(self, attrname):
  11.         if attrname == "lol":
  12.             print("lol")
  13.         else:
  14.             raise AttributeError(attrname)
复制代码


这样可能会减少不必要的打印,但注意这只是一个示例,实际使用中需根据需求调整。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 昨天 15:33 | 显示全部楼层    本楼为最佳答案   
你好!我来解释一下为什么 __getattribute__ 方法会导致 "why" 被多次打印。

首先,__getattribute__ 方法在每次访问对象的任何属性时都会被调用(包括内部属性)。你的代码中,这个方法被重写为每次调用时都打印 "why",然后通过 super().__getattribute__(attrname) 返回属性值。

在 IDLE 中执行 c.x 时,"why" 被打印三次的原因如下:
  • 第一次打印:直接访问 c.x 触发 __getattribute__("x")
  • 第二次和第三次打印:当属性 x 不存在时,Python 会调用 __getattr__("x"),但在这个过程中,异常处理或 Traceback 显示可能会额外访问对象的其他属性(例如 __class____dict__),从而再次触发 __getattribute__


在 PyCharm 控制台中,实例化对象时打印更多次 "why",是因为控制台环境通常会立即调用对象的 __repr__ 方法(用于显示对象),而默认的 __repr__ 会访问多个基础属性(如 __class____dict__ 等),每次访问都会触发 __getattribute__

简单来说,任何属性访问(包括 Python 内部操作)都会导致 "why" 被打印。如果你不希望这样,可以调整 __getattribute__ 的实现,例如避免在访问特定属性时打印。

示例代码修改(避免无限递归):

  1. class C:
  2.     def __init__(self, name, age):
  3.         self.name = name
  4.         self.__age = age
  5.     def __getattribute__(self, attrname):
  6.         # 只在访问非特殊属性时打印
  7.         if not attrname.startswith('__'):
  8.             print("why")
  9.         return super().__getattribute__(attrname)
  10.     def __getattr__(self, attrname):
  11.         if attrname == "lol":
  12.             print("lol")
  13.         else:
  14.             raise AttributeError(attrname)
复制代码


这样可能会减少不必要的打印,但注意这只是一个示例,实际使用中需根据需求调整。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 15:40 | 显示全部楼层
FishC 发表于 2025-11-6 15:33
你好!我来解释一下为什么 __getattribute__ 方法会导致 "why" 被多次打印。

首先,__getattribute__ 方 ...

我在网上搜了好久都没见过相似的问题,没想到一下就被解答了十分强大
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 15:40 | 显示全部楼层
qwe8885656 发表于 2025-11-06 15:40
FishC 发表于 2025-11-6 15:33
你好!我来解释一下为 ...

我在网上搜了好久都没见过相似的问题,没想到一下就被解答了十分强大


很高兴能帮到你!这个问题确实比较隐蔽,因为涉及到了Python内部机制和不同IDE的调试行为差异。

__getattribute__
这个魔法方法确实需要小心使用,因为它会拦截所有的属性访问,包括Python解释器内部的操作。

如果你只是想处理特定属性的访问,建议优先考虑使用__getattr__,它只在属性不存在时才会被调用,这样就不会干扰Python的正常运行了。

有什么其他Python问题随时可以来问!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 15:49 | 显示全部楼层
FishC 发表于 2025-11-6 15:40
很高兴能帮到你!这个问题确实比较隐蔽,因为涉及到了Python内部机制和不同IDE的调试行为差异。

...

还有一个问题是,在小甲鱼的课程中演示版本是python3.9.12,在同样的代码下并没有出现相同的问题,请问是在某个版本python做了什么修改,引发了出现这种问题的可能性吗?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 15:50 | 显示全部楼层
qwe8885656 发表于 2025-11-06 15:49
FishC 发表于 2025-11-6 15:40
很高兴能帮到你!这个 ...


很好的观察!确实在不同Python版本中可能会有不同的行为。

Python 3.9到3.14之间确实有一些关于属性访问和异常处理的内部优化和修改。可能的原因包括:

1. 异常处理的改进
- 新版本可能在处理AttributeError时会有更多的内部属性访问
- 异常回溯机制可能更加详细,需要访问更多对象信息

2. 交互式环境的优化
- IDLE和PyCharm的控制台在新版本中可能对对象显示有更多内部查询
- 调试信息的获取方式可能发生了变化

3. 属性访问机制的调整
- Python内部对__getattribute__的调用机制可能有细微调整
- 属性查找链的优化可能导致额外的访问

4. 版本差异验证
你可以在两个版本中都运行这个简单测试:


  1. class Test:
  2.     def __getattribute__(self, name):
  3.         print(f"访问属性: {name}")
  4.         return super().__getattribute__(name)

  5. t = Test()
  6. print("--- 实例化完成 ---")
  7. t.non_existent_attr
复制代码


对比两个版本的输出差异,就能看到内部访问模式的变化。

这确实是Python版本演进中可能遇到的有趣现象!建议在实际项目中谨慎使用__getattribute__,因为它会影响所有属性访问的性能和预期行为。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-11-7 04:45

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表