python __getattr__ & __getattribute__ 学习

实例属性的获取和拦截, 仅对实例属性(instance, variable)有效, 非类属性#

getattr: 适用于未定义的属性, 即该属性在实例中以及对应的类的基类以及祖先类中都不存在
1. 动态处理事先未定义的属性, 可更好的实现数据隐藏, 当调用dir(obj)时只会显示初始化定义的正常的属性和方法
getattribute: 对于所有属性的访问都会调用该方法, 当属性不存在时会报错
1. 覆盖该方法之后,任何属性的访问都会调用用户自定义的__getattribute__()方法, 性能上会有所损耗.

  1. 当两个方法同步被重写, 要么在__getattribute__()中显示调用, 要么是触发AttributeError异常时, getattr()才会被调用
  2. 要避免无穷递归调用
  3. 如果访问未定义属性, 且在__getattr__中未跑出AttributeError异常或者显性的返回一个值, 则会返回None

参考: 编写高质量代码:改善Python程序的91个建议#

Copy
class Attribute(object): def __init__(self, name): self.name = name def __getattribute__(self, key): try: print('calling __getattribute__.{key}'.format(key=key)) # 调用超类 return super(Attribute, self).__getattribute__(key) # return object.__getattribute__(self, key) except KeyError: return 'default' except AttributeError as ex: # 捕获了该异常就不用调用__getattr__ print(ex) def __getattr__(self, key): # 什么时候被调用: # 1.当属性不在实例以及基类和祖先类的__dict__ # 2. 当触发AtrributeError异常时(不仅仅是__getattribute__()引发的 AttributeError),porperty中定义的get()方法也会抛出异常 print('calling __getattr__.{key}'.format(key=key)) # return 'default'

测试 property, getattribute, __getattr__调用顺序#

Copy
class A(object): _c = 'test' def __init__(self): self.x = None @property def a(self): print('using property to access attribute') if self.x is None: print('return value') return 'a' else: print('error occured') raise AttributeError @a.setter def a(self, value): self.x = value def __getattribute__(self, name): print('using __getattribute__ to access attribute') return object.__getattribute__(self, name) def __getattr__(self, name): print('using __getattr__ to access attribute') print('attribute name: ', name) return 'b' if __name__ == '__main__': a = Attribute('atest') print(a.name) print(a.test) # 测试 property, __getattribute__, __getattr__调用顺序 # b = A() # print(b.a) # print('-'*50) # b.a = 10 # print(b.a) # print('-'*50) # print(A._c)

defaultdict 和 魔法方法__missing__()#

dict中并不存在__missing__()方法, 需要派生子类并重写__missing__()方法

Copy
# python 2.5 之前默认要自己重写__missing__方法 # python3以后 __missing__(key) called by __getitem__ for missing key; class DefaultDict(dict): def __init__(self, default_factory, *args, **kwargs): super(DefaultDict, self).__init__(*args, **kwargs) self.default_factory = default_factory def __getitem__(self, key): try: return dict.__getitem__(self, key) except KeyError: return self.__missing__(key) def __missing__(self, key): self[key] = value = self.default_factory() return value
posted @   JonPan  阅读(274)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示
CONTENTS