【问题标题】:python decorator for field字段的python装饰器
【发布时间】:2012-11-12 00:53:06
【问题描述】:

我知道没有这样的事情。这就是为什么我正在寻找一些不错的等价物。有这个类:

class MyClass:
   a = 5
   b  = "foo"
   c = False

我想将 a 和 b 字段“分组”在一起,以便能够以某种方式仅迭代来自该组的成员。所以最好有某种字段装饰器,比如:

class MyClass:
   @bar
   a = 5
   @bar
   b  = "foo"
   c = False

还有一些像 myDir(MyClass, 'bar') 这样会返回 ('a', 'b') 的函数。

到目前为止,我们有哪些选择? 1. 按特殊约定命名这些字段,例如“a_bar”、“b_bar”——但不幸的是我不能这样做。 2. 将名称列表作为另一个类成员 - 我想让这个分组属性接近属性,所以我不喜欢这种方法。 3.我可以创建从整数和字符串继承的类,并添加另一个基类,如“Group”,然后检查类型,而不是将 5 分配给“a”和“foo”,这样我就必须生成这个类每次我都有新类型,所以我也不喜欢这个解决方案。

还有其他想法吗?

【问题讨论】:

  • 我想说#2 是要走的路。这是迄今为止最简单、最不老套的方法。
  • 所以我忘了写 - 我想从这个列表中获得一些想法;)
  • “保持这个分组属性接近属性”到底是什么意思?您是指字典的键值存储属性吗?
  • 我想把它作为这个属性的属性,而不是整个类的属性。这样我就可以避免在列表中重复属性的名称。
  • @mnowotka 是的,我怀疑。因此,这是一个评论,而不是更长的理由,为什么 #2 是最好的。不过,我是认真的:我认为这是迄今为止你能得到的最好的。

标签: python design-patterns decorator


【解决方案1】:

装饰器只是函数调用的语法糖,因此要将装饰器应用于属性,您只需在初始化程序上调用它:

a = bar(5)

在您的情况下,您可以创建实现描述符协议的对象:

class GroupedAttribute(object):
    def __init__(self, group, obj):
        self.group = group
        self.obj = obj
    def __get__(self, obj, owner):
        return self.obj
    def __set__(self, obj, value):
        self.obj = value

为了优雅,您可以为属性组编写一个类:

class GroupedAttribute(object):
    def __init__(self, group, obj):
        self.group = group
        self.obj = obj
    def __get__(self, obj, owner):
        return self.obj
    def __set__(self, obj, value):
        self.obj = value

class AttributeGroup(object):
    def __call__(self, obj):
        return GroupedAttribute(self, obj)
    def __get__(self, obj, owner):
        return BoundAttributeGroup(self, obj, owner)

class BoundAttributeGroup(object):
    def __init__(self, group, obj, owner):
        self.group = group
        self.obj = obj
        self.owner = owner
    def __dir__(self):
        items = dir(self.owner if self.obj is None else self.obj)
        return [item for item in items if
                getattr(self.owner.__dict__.get(item, None),
                        'group', None) is self.group]

用法:

class MyClass(object):
    bar = AttributeGroup()
    a = bar(5)
    b = bar("foo")
    c = False
dir(MyClass.bar)    # ['a', 'b']

【讨论】:

  • 我想这可能是一个绝妙的答案,但坦率地说,我就是不明白。你能扩展它并举例说明如何实际使用你的代码吗?
  • 描述符是一个对象,一旦设置在属性上,如果您获取或设置此属性,它将执行任意代码。 @ecatmur 通过创建一个描述符为您提供解决方案,该描述符将正常设置和获取属性,但另外还按您在初始化时为其指定的名称对属性进行分组。
  • 我会将这个答案标记为已接受,但实际上最糟糕的答案是@delnan 在 cmets 中给出的答案。
【解决方案2】:

如果您想保留变量名称以供以后参考,您可以使用字典。因此,您的对象中的这段代码......

self.dict_bar_props = {}

self.dict_bar_props["a"] = 5
self.dict_bar_props["b"] = "foo"
self.dict_bar_props["c"] = False

...稍后访问对象的属性时会给你这个结果:

objectName = myObject()
objectName.dict_bar_props["a"]
>> 5

如果您想将变量名完全分开,但稍后根据定义的命名约定找到它们,那么您可以使用仅返回以“bar_”为前缀的变量名的 hacky,例如:

import re
varnames = dir(objectName)
list_of_property_names    = [ a for a in varnames if re.match("bar_", a) ]

【讨论】:

  • 我很抱歉这么说,但您似乎没有理解这个问题:(
  • 只要字典是您的“相关字段组”,您绝对可以使用 dict_bar_props.keys() / values() 或 dict_bar_props.iteritems() 遍历其中的项目。您能否提供一个预期行为的示例,以说明这不能满足您的需求?
  • 我还添加了第二种解决方案,它是选项 1 和 2 的维护成本略低的混合体。
  • 是的。所以你看它是一个混合体。我正在从这个列表中寻求一些东西。反正这个组合的结果还是无效的。
猜你喜欢
  • 2019-07-09
  • 1970-01-01
  • 1970-01-01
  • 2013-08-07
  • 2014-01-23
  • 2020-02-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多