Python装饰器用于字段

9

我知道没有完全相同的东西,所以我在寻找一些很好的替代品。有了这个类:

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. 不是将 5 分配给 'a',将 "foo" 分配给 b,而是制作从整数和字符串继承的类,并添加另一个基类 'Group',然后检查类型 - 这样我每次有新类型时都需要生成这个类,所以我也不喜欢这个解决方案。

还有其他的想法吗?


3
我认为方案二是可行的。它明显是最简单和最少折衷的方法。 - user395760
所以我忘记写了 - 我想要一些不在这个列表中的想法 ;) - mnowotka
你所说的“将这个分组属性保持靠近属性”,具体是什么意思?也许你指的是字典的键值存储属性吗? - abought
我希望将它作为该属性的属性,而不是整个类的属性。这样我就能避免在列表中重复属性名称了。 - mnowotka
@mnowotka 是的,我也怀疑。这就是为什么它是一个评论而不是更长的理由,说明为什么#2是最好的。尽管如此,我很认真:我认为这是迄今为止你能得到的最好的。 - user395760
@delnan - 我想是这样,但我想确保没有更好的想法。 - mnowotka
2个回答

8

装饰器只是函数调用的语法糖,所以要将装饰器应用到属性上,您只需要在初始化器上调用它:

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

为了简洁,您可以为属性组编写一个类:
```html

为了优雅起见,您可以编写一个用于属性组的类:

```
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']

1
我想这可能是个很棒的答案,但坦白地说,我并不理解。你能否扩展一下,并给出一个如何实际使用你的代码的例子? - mnowotka
描述符是一个对象,一旦设置在属性上,如果您获取或设置此属性,它将执行任意代码。@ecatmur为您提供了一个解决方案,通过创建一个描述符来正常设置和获取属性,但另外按照您在初始化时指定的名称对属性进行分组。 - Bite code
我会将此答案标记为已接受,但实际上最佳答案是由@delnan在评论中给出的。 - mnowotka

0
如果您想保留变量名称以供以后引用,可以使用字典。因此,在您的对象中,这段代码可能如下所示...
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_”为前缀的变量名称,例如:
import re
varnames = dir(objectName)
list_of_property_names    = [ a for a in varnames if re.match("bar_", a) ]

很抱歉,但是看起来你没有理解这个问题 :( - mnowotka
就字典而言,它是您的“相关字段组”,您绝对可以使用dict_bar_props.keys() / values()或dict_bar_props.iteritems()迭代其中的项。您能否提供一个预期行为的示例,以澄清这种方法如何无法满足您的需求? - abought
我还添加了第二个解决方案,它是选项1和2的混合,维护成本略低。 - abought
是的。所以你看它是一个混合体。我正在寻求这个列表之外的东西。无论如何,这种组合的结果仍然无效。 - mnowotka

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接