如何同时设置多个对象的属性

如何同时设置多个对象的属性

本文介绍了一种在 python 中使用通配符批量设置多个对象属性的方法。通过创建一个中间类 registersView,可以拦截属性的设置和获取操作,并将这些操作传播到一组 Register 对象上,从而实现同时修改多个寄存器值的目标。

在处理具有多个相似对象(例如寄存器)的场景时,经常需要同时修改它们的属性。如果使用循环逐个修改,代码会显得冗长且不易维护。本文提供一种优雅的解决方案,通过引入一个中间类,利用 Python 的魔术方法 __setattr__ 和 __getattr__ 拦截属性访问,实现批量设置属性的功能。

实现原理

核心思想是创建一个 RegistersView 类,该类持有一个 Register 对象列表。当通过 RegistersView 实例设置属性时,__setattr__ 方法会被调用,该方法遍历 RegistersView 内部的 Register 列表,并将属性设置应用到每个 Register 对象上。类似地,当获取属性时,__getattr__ 方法会被调用,该方法返回一个包含所有 Register 对象对应属性值的列表。

代码示例

首先,定义一个简单的 Register 类:

class Register:     def __init__(self, name, value=0):         self.name = name         self.value = value      def __repr__(self):         return str(self.value)

接下来,创建 RegistersView 类:

class RegistersView:     _registers: list[Register]      def __init__(self, registers: list[Register]):         self._registers = registers      def __setattr__(self, key, value):         if key in ["_registers"]:             super().__setattr__(key, value)         else:             for r in self._registers:                 setattr(r, key, value)      def __getattr__(self, item):         if item in ["_registers"]:             super().__getattribute__(item)         else:             return [getattr(r, item) for r in self._registers]

最后,修改 Memory 类,使其在 __getitem__ 方法中返回 RegistersView 实例:

import fnmatch  class Memory:     _registers: dict      def __init__(self):         self._registers = {             "registerName1": Register("registerName1"),             "registerName2": Register("registerName2"),             "registerName3": Register("registerName3"),         }      def __getitem__(self, registerId):         if '*' in registerId or '?' in registerId:             regs = list(filter(lambda register: fnmatch.fnmatch(register.name, registerId), self._registers.values()))             return RegistersView(regs)          return self._registers[registerId]      def __repr__(self):         return f"MEMO {self._registers}"  if __name__ == '__main__':     aMemory = Memory()     print(aMemory)     # MEMO {'registerName1': 0, 'registerName2': 0, 'registerName3': 0}      aRegister = aMemory["registerName1"]     aRegister.value = 12      allReg = aMemory["registerName*"]     print(aMemory, allReg.value)     # MEMO {'registerName1': 12, 'registerName2': 0, 'registerName3': 0} [12, 0, 0]      allReg.value = 14     print(aMemory, allReg.value)     # MEMO {'registerName1': 14, 'registerName2': 14, 'registerName3': 14} [14, 14, 14]

使用方法

  1. 创建 Memory 实例。
  2. 使用带有通配符的键访问 Memory 实例,例如 aMemory[“registerName*”]。这将返回一个 RegistersView 实例。
  3. 通过 RegistersView 实例设置属性,例如 allReg.value = 14。这将同时修改所有匹配的 Register 对象的 value 属性。

注意事项

  • RegistersView 类仅用于批量设置属性,如果需要对单个 Register 对象进行操作,可以直接通过 Memory 实例访问,例如 aMemory[“registerName1”].value = 12。
  • RegistersView 类的 __getattr__ 方法返回一个列表,包含所有匹配的 Register 对象的对应属性值。在使用时需要注意处理列表。
  • 通配符匹配使用 fnmatch 模块,支持 * 和 ? 等通配符。

总结

通过引入 RegistersView 类,可以方便地实现批量设置多个对象属性的功能,避免了使用循环的繁琐。这种方法不仅简洁高效,而且提高了代码的可读性和可维护性。在处理具有多个相似对象的场景时,可以考虑使用这种方法来简化代码。

© 版权声明
THE END
喜欢就支持一下吧
点赞14 分享