【问题标题】:Adding properties dynamically to a Python class that point to items in a dictionary将属性动态添加到指向字典中项目的 Python 类
【发布时间】:2020-12-16 20:33:16
【问题描述】:

我正在尝试将属性动态附加到类 (Registry),以便轻松访问 dict 中的值。我使用defaultdict定义字典,默认值为空list

但是由于我在定义属性时访问字典中的列表值的方式,我最终得到的所有属性都指向同一个列表对象。

要点:https://gist.github.com/subhashb/adb75a3a05a611c3d9193da695d46dd4


from collections import defaultdict
from enum import Enum


class ElementTypes(Enum):
    PHONE = "PHONE"
    CAR = "CAR"


class Registry:
    def __new__(cls, *args, **kwargs):
        cls.setup_properties()
        instance = super(Registry, cls).__new__(cls, *args, **kwargs)
        return instance

    def __init__(self):
        self._elements = {}

    def register(self, element_type, item):
        if element_type.value not in self._elements:
            self._elements[element_type.value] = []

        self._elements[element_type.value].append(item)

    def get(self, element_type):
        return self._elements[element_type.value]

    @classmethod
    def setup_properties(cls):
        for item in ElementTypes:
            prop_name = item.value
            prop = property(lambda self: getattr(self, "get")(item))

            setattr(Registry, prop_name.lower(), prop)


registry = Registry()
registry.register(ElementTypes.PHONE, "phone1")
registry.register(ElementTypes.PHONE, "phone2")
registry.register(ElementTypes.CAR, "car1")
registry.register(ElementTypes.CAR, "car2")

assert dict(registry._elements) == {
    "CAR": ["car1", "car2"],
    "PHONE": ["phone1", "phone2"],
}
assert hasattr(registry, "phone")
assert hasattr(registry, "car")

assert registry.car == ["car1", "car2"]
assert registry.phone == ["phone1", "phone2"]  # This fails

如何定义带有属性的代码才能真正动态地访问字典中的各个列表值?

【问题讨论】:

  • 你把事情复杂化了。您只需要一个点表示法 dict 包装器,例如 thisthat(还有更多示例,只需搜索“python dict dot notation”)

标签: python python-3.x


【解决方案1】:

首先,不要在__new__ 中设置属性,因为创建的每个Registry 对象都会调用该属性!相反,只需在类定义之外分配属性。

其次,这会让很多人失望,但如果您在 for 循环中使用 lambda 并且想要使用 item 变量,则需要确保添加一个名为 @987654325 的参数@ 使用默认值item,否则所有属性将引用循环的最后一个item

class Registry:
    def __init__(self):
        self._elements = defaultdict(list)

    def register(self, element_type, item):
        self._elements[element_type.value].append(item)

    def get(self, element_type):
        return self._elements[element_type.value]


for item in ElementTypes:
    prop_name = item.value
    prop = property(lambda self, item=item: self.get(item))

    setattr(Registry, prop_name.lower(), prop)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 2019-04-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多