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

问题描述 投票:0回答:2

我构建了一个 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 上的那个,我也不确定我是否可以完成这项工作。

所以我想我的问题是:有什么方法可以实现这一点,或者我是否必须创建一个函数来在使用通配符时设置所有寄存器?

python dictionary wildcard
2个回答
0
投票

您可以创建一个包含多个

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]

0
投票

你可以使用另一个覆盖

__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)])
© www.soinside.com 2019 - 2024. All rights reserved.