更新 class 中字典中使用的 属性

Updating a property used in dict in a class

我正在尝试实现动态更新对象中的一些参数。 让我们在某些字典中使用 属性 ->

class Test():
    def __init__(self):
        self._id = None
        self.some_dict = {"id": self.id}

    @property
    def id(self):
        return self._id

    @id.setter
    def id(self, new_id: int):
        self._id = new_id

tst = Test()
tst.id = 112
print(tst.id) # 112
print(tst.some_dict) # {'id': None}

期望的结果是:

print(tst.some_dict) # {'id': 112}

如何在某些参数 (id) 之后更新字典,因为 属性 将被更新?

编辑: 我当然可以做到:

@id.setter
def id(self, new_id: int):
    self._id = new_id
    self._some_dict.update({"id": self._id})

但是很多参数写起来有点累,有没有自动的办法?

您必须将行 self.some_dict['id'] = new_id 添加到 def id

您可以访问实例的 __dict__ 属性和 return 此 dict 的净化版本。

示例:(应该按原样工作)

class A:
    _prohibited_keys = ["instance", "variables", "you", "dont", "want", "to", "show"]

    def __init__(self):
        self._id = None
    @property
    def id(self):
        return self._id

    @id.setter
    def id(self, value: int):
        self._id = value

    @property
    def dict(self):
        return {self._private_to_pub_key(k): v for k, v in self.__dict__.items()
                if k not in self._prohibited_keys and not k.startswith('__')}

    def _private_to_pub_key(self, k):
        return k[1:] if k.startswith('_') else k




a = A()
print(a.dict)
>>> {'id': None}
class Test():
    def __init__(self):
        self._id = None
        self.some_dict = {"id": self.id}
    
    @property
    def id(self):
        return self._id
    
    @id.setter
    def id(self, new_id: int):
        self._id = new_id
        self.some_dict['id'] = new_id



tst = Test()
tst.id = 112
print(tst.id) # 112
print(tst.some_dict) # {'id': 112}

您可以在 id.setter 函数中更新它:

    @id.setter
    def id(self, new_id: int):
        self._id = new_id
        self.some_dict.update({'id': new_id})

在某种程度上可以实现自动化,就像消除大量重复编码一样。在下面的代码中,这是通过结合使用创建属性的效用函数以及 post 处理 class 定义并初始化字典的元 class 来完成的也想要它也有

后者涉及搜索那些已定义的实例并初始化与其 属性 名称关联的实例存储属性以及此附加字典中的相应项目。这个要求使得 class 实例的创建变得如此复杂,尤其是需要有一个 metaclass — 所以你可能想重新考虑这是否真的有必要。

def dict_property(name):
    """ Define property with given name that updates a private attribute and the
        instance's dictionary named some_dict.
    """
    storage_name = '_' + name

    @property
    def prop(self):
        return getattr(self, storage_name)

    @prop.setter
    def prop(self, value):
        setattr(self, storage_name, value)
        self.some_dict.update({name: value})

    return prop


class MyMetaClass(type):
    def __new__(cls, name, bases, classdict, **kwargs):
        """ Initialize dict_property values in class and some_dict to None. """

        names = []
        for name, value in classdict.items():
            if isinstance(value, property):
                #print(f'found property named {name!r}')
                names.append(name)

        some_dict = {}
        for name in names:
            storage_name = '_' + name
            classdict[storage_name] = None
            some_dict[name] = None

        classdict['some_dict'] = some_dict  # Add dict to class.

        # Create the class.
        return type.__new__(cls, name, bases, classdict, **kwargs)


class Test(metaclass=MyMetaClass):
    id = dict_property('id')
    age = dict_property('age')


tst = Test()
print(f'{tst.id=}')         # -> tst.id=None
print(f'{tst.age=}')        # -> tst.age=None
print(f'{tst.some_dict=}')  # -> tst.some_dict={'id': None, 'age': None}
print()
tst.id = 112
print(f'{tst.id=}')         # -> tst.id=112
print(f'{tst.age=}')        # -> tst.age=None
print(f'{tst.some_dict=}')  # -> tst.some_dict={'id': 112, 'age': None}
print()
tst.age = 42
print(f'{tst.id=}')         # -> tst.id=112
print(f'{tst.age=}')        # -> tst.age=42
print(f'{tst.some_dict=}')  # -> tst.some_dict={'id': 112, 'age': 42}

尝试 @property 装饰器 some_dict:

class Test():
    def __init__(self):
        self._id = None

    @property
    def id(self):
        return self._id

    @id.setter
    def id(self, new_id: int):
        self._id = new_id

    @property
    def some_dict(self):
        return {'id': self.id}

tst = Test()
tst.id = 112
print(tst.id) # 112
print(tst.some_dict) # {'id': 112}