我构建了一个 Memory 类来表示一种内存,这种内存有一堆 Register 类的寄存器,为了简单起见,我们只说它们有一个名称和一个值作为属性。
这个类的构建就像字典一样工作,因此我可以通过名称访问每个寄存器。
例如:
aMemory = Memory()
aRegister = aMemory["registerName1"] #Gets an object of type Register with name "registerName1"
这让我可以做到:
aMemory["registerName1"].value = 12
直接设置寄存器值。
现在假设我有 3 个寄存器:“registerName1”、“registerName2”和“registerName3”
我想做:
aMemory["registerName*"].value = 12 #Notice the '*' wildcard
并期望将所有匹配寄存器的值设置为 12。
我尝试的是为 Memory 类实现
__getitem__()
函数,当检测到键上的通配符时,它将返回某种生成器,例如:
def __getitem__(self, registerId):
if '*' in registerId or '?' in registerId:
return filter(lambda register: fnmatch.fnmatch(register.name, registerId), self._registers.values())
return self._registers[registerId]
否则将返回带有该键的 Register 对象。
现在这显然不起作用,因为接下来要调用的
__setattr__()
是过滤器对象上的,而不是 Register 对象上的。但即使我可以调用 Register 上的那个,我也不确定我是否可以完成这项工作。
所以我想我的问题是:有什么方法可以实现这一点,或者我是否必须创建一个函数来在使用通配符时设置所有寄存器?
您可以创建一个包含多个
Register
的类,当您在其上设置/获取属性时,它会将其传播到每个 Register
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]
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]
你可以使用另一个覆盖
__setattr__
的类来伪造它。
import fnmatch
class WildCard:
def __init__(self, registers, string):
self.string = string
self._registers = registers
def __setattr__(self, name, value):
if name in ('string',"_registers"):
return super().__setattr__(name,value)
items = filter(lambda register: fnmatch.fnmatch(register.name, self.string), self._registers.values())
for item in items:
item.__setattr__(name,value)
class Register():
def __init__(self, name, value):
self.name = name
self.value = value
def __repr__(self):
return f"Register(name = {self.name}, value = {self.value})"
class Memory:
def __init__(self, registers = {}):
self._registers = registers
def __getitem__(self, registerId):
if '*' in registerId or '?' in registerId:
return WildCard(self._registers, registerId)
return self._registers[registerId]
var = Memory({'A':Register('A',1), "AA":Register('AA',2)})
var['A*'].value = 0
print(var._registers.values())
dict_values([Register(name = A, value = 0), Register(name = AA, value = 0)])