gpt4 book ai didi

Python:从列表动态生成属性

转载 作者:行者123 更新时间:2023-12-04 09:31:51 25 4
gpt4 key购买 nike

我希望能够从列表或字典动态生成类的属性。这个想法是我可以定义一个属性列表,然后能够使用 my_class.my_attribute 访问这些属性。
例如:

class Campaign(metaclass=MetaCampaign):
_LABELS = ['campaign_type', 'match_type', 'audience_type'] # <-- my list of attributes

for label in _LABELS:
setattr(cls, label, LabelDescriptor(label))

def __init__(self, campaign_protobuf, labels)
self._proto = campaign_protobuf
self._init_labels(labels_dict)

def _init_labels(self, labels_dict):
# magic...
这显然行不通,因为 cls不存在,但我想:
my_campaign = Campaign(campaign, label_dict)
print(my_campaign.campaign_type)
返回值 campaign_typecampaign .这显然有点复杂,如 campaign_type实际上是 Descriptor并做了一些工作来从基中检索值 Label目的。

描述符:
class DescriptorProperty(object):
def __init__(self):
self.data = WeakKeyDictionary()

def __set__(self, instance, value):
self.data[instance] = value


class LabelTypeDescriptor(DescriptorProperty):
"""A descriptor that returns the relevant metadata from the label"""
def __init__(self, pattern):
super(MetaTypeLabel, self).__init__()
self.cached_data = WeakKeyDictionary()
# Regex pattern to look in the label:
# r'label_type:ThingToReturn'
self.pattern = f"{pattern}:(.*)"

def __get__(self, instance, owner, refresh=False):
# In order to balance computational speed with memory usage, we cache label values
# when they are first accessed.
if self.cached_data.get(instance, None) is None or refresh:
ctype = re.search(self.pattern, self.data[instance].name) # <-- does a regex search on the label name (e.g. campaign_type:Primary)
if ctype is None:
ctype = False
else:
ctype = ctype.group(1)
self.cached_data[instance] = ctype
return self.cached_data[instance]
这使我可以轻松访问标签的值,如果标签是我关心的类型,则返回相关值,否则返回 False .

标签对象:
class Label(Proto):
_FIELDS = ['id', 'name']
_PROTO_NAME = 'label'
# We define what labels can pull metadata directly through a property
campaign_type = LabelTypeDescriptor('campaign_type')
match_type = LabelTypeDescriptor('match_type')
audience_type = LabelTypeDescriptor('audience_type')

def __init__(self, proto, **kwargs):
self._proto = proto
self._set_default_property_values(self) # <-- the 'self' is intentional here, in the campaign object a label would be passed instead.

def _set_default_property_values(self, proto_wrapper):
props = [key for (key, obj) in self.__class__.__dict__.items() if isinstance(obj, DescriptorProperty)]
for prop in props:
setattr(self, prop, proto_wrapper)
因此,如果我的 Label(基本上只是一个包装器)中存储了一个 protobuf 标签对象,如下所示:
resource_name: "customers/12345/labels/67890"
id {
value: 67890
}
name {
value: "campaign_type:Primary"
}
然后 my_label.campaign_type会返回 Primary ,类似地 my_label.match_type会返回 False
原因是我正在创建许多以相同方式标记的类,并且可能有很多标签。目前这一切都按照描述的方式工作,但我希望能够更动态地定义属性,因为它们基本上都遵循相同类型的模式。所以而不是:
    campaign_type = LabelTypeDescriptor('campaign_type')
match_type = LabelTypeDescriptor('match_type')
audience_type = LabelTypeDescriptor('audience_type')
... # (many more labels)
我只有: _LABELS = ['campaign_type', 'match_type', 'audience_type', ... many more labels]然后有一些循环来创建属性。
反过来,我可以将类似的方法级联到我的其他类中,这样虽然 Campaign对象可能包含 Label对象,我可以简单地通过 my_campaign.campaign_type 访问标签的值.如果广告系列没有合适类型的标签,它只会返回 False .

最佳答案

虽然 cls类体运行时不存在,可以通过在locals()返回的字典中设置then来设置属性。在类体内:

class Campaign(metaclass=MetaCampaign):
_LABELS = ['campaign_type', 'match_type', 'audience_type'] # <-- my list of attributes

for label in _LABELS:
locals()[label] = label, LabelDescriptor(label)
del label # so you don't get a spurious "label" attribute in your class


除此之外,您可以使用元类,是的,但也可以使用 __init_suclass__在基类上。更少的元类意味着更少的“移动部件”可以在您的系统中以奇怪的方式运行。
所以,说你的 Proto class 是所有其他需要此功能的基础:
class Proto:
def __init_subclass__(cls, **kwd):
super().__init_subclass__(**kwd)
for label in cls._LABELS:
setattr(cls, label, LabelDescriptor(label))
...
我看过你的描述符和那里的代码 - 如果它们已经在工作,我会说它们没问题。
我可以评论说,将描述符相关的数据存储在实例的 __dict__ 中更为常见。本身,而不是创建 datacached_data在描述符本身中 - 所以人们不需要关心弱引用 - 但两种方法都有效(就在本周,我已经以这种方式实现了一个描述符,即使我通常去实例的 __dict__ )

关于Python:从列表动态生成属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62810416/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com