2009-05-25 74 views
16

比方说,我有下面的类在子类扩展一个类属性的一个巧妙的办法

class Parent(object): 
    Options = { 
     'option1': 'value1', 
     'option2': 'value2' 
    } 

和被称为儿童

class Child(Parent): 
    Options = Parent.Options.copy() 
    Options.update({ 
     'option2': 'value2', 
     'option3': 'value3' 
    }) 

我希望能够覆盖或添加选项子孩子班。我正在使用的解决方案。但我相信有一个更好的方法来做到这一点。


编辑

我不想为类的属性,因为我有没有选择其他类的属性,我宁愿保持所有选项在一个地方添加选项。这只是一个简单的例子,实际的代码比这更复杂。

+0

的方式为什么不出货父类的方法复制/更新逻辑?如果你把它放在`__init__`中,并且总是在子类`__init__`的末尾调用`super().__ init __()`,就像你应该这样做,它应该可以工作。 – asmeurer 2013-06-16 20:56:25

回答

8

一种方法是使用关键字参数与dict指定其他键:

Parent.options = dict(
    option1='value1', 
    option2='value2', 
) 

Child.options = dict(Parent.options, 
    option2='value2a', 
    option3='value3', 
) 

如果你想更大胆的尝试,然后使用描述协议,您可以创建一个代理对象这将封装查找。 (只需将owner .__ mro__从owner属性移动到__get __(self,instance,owner)方法)。甚至更有趣,进入可能不是一个好主意的领域,metaclasses /类装饰。

4

为什么不直接使用类属性?

class Parent(object): 
    option1 = 'value1' 
    option2 = 'value2' 

class Child(Parent): 
    option2 = 'value2' 
    option3 = 'value3' 
+0

你,赢了。打我20秒:) – SpliFF 2009-05-25 16:41:33

+0

我更喜欢在一个属性中保留选项,因为我有其他类属性不是选项。 – 2009-05-25 16:50:39

+0

您可以用一个前缀标记特殊的attirbutes,例如`opt_foo`和`opt_bar`,然后访问例如`[getattr(self,x)for x in dir(self)if x。startswith(“opt _”)]` – 2012-11-05 15:03:29

2
class ParentOptions: 
    option1 = 'value1' 
    option2 = 'value2' 

class ChildOptions(ParentOptions): 
    option2 = 'value2' 
    option3 = 'value3' 

class Parent(object): 
    options = ParentOptions() 

class Child(Parent): 
    options = ChildOptions() 
21

语义上等同于你的代码,但可以说是整洁:

class Child(Parent): 
    Options = dict(Parent.Options, 
     option2='value2', 
     option3='value3') 

记住,“生活是没有括号更好”,并通过调用dict明确你常常可以避开括号(和额外的引号是常数标识符关键字类似的字符串)。

更多细节请http://docs.python.org/library/stdtypes.html#dict - 关键位是“如果两个在位置参数和作为关键字参数指定的密钥,与关键字相关联的值被保留的”,即关键字ARGS 倍率键 - 值的关联在位置arg中,就像update方法可以让你覆盖它们)。

6

想更多地了解它后,并感谢@SpliFF建议这是我想出了:

class Parent(object): 
    class Options: 
     option1 = 'value1' 
     option2 = 'value2' 


class Child(Parent): 
    class Options(Parent.Options): 
     option2 = 'value2' 
     option3 = 'value3' 

我还是开到更好的解决方案虽然。

2

下面是使用元类

class OptionMeta(type): 
    @property 
    def options(self): 
     result = {} 
     for d in self.__mro__[::-1]: 
      result.update(getattr(d,'_options',{})) 
     return result 

class Parent(object): 
    __metaclass__ = OptionMeta 
    _options = dict(
     option1='value1', 
     option2='value2', 
     ) 

class Child(Parent): 
    _options = dict(
     option2='value2a', 
     option3='value3', 
     ) 

print Parent.options 
print Child.options