【问题标题】:Python update inherited class level dictionaryPython更新继承的类级别字典
【发布时间】:2012-01-28 15:53:15
【问题描述】:

我正在寻找一种干净、简单的方法来更新继承自基类的类级别字典。例如:

class Foo(object):
    adict = {'a' : 1}

class Bar(Foo):
    adict.update({'b' : 2})  # this errors out since it can't find adict

这样:

Foo.adict == {'a' : 1}
Bar.adict == {'a' : 1, 'b' : 2}

我不想在这里使用实例,如果可能的话也不要使用类方法。

【问题讨论】:

    标签: class inheritance dictionary python-3.x


    【解决方案1】:

    请注意,即使这样有效,您也需要更新同一个字典而不是创建新字典(因此 Foo.adict is Bar.adictFoo.adict == Bar.adict)。

    无论如何,最简单的方法是显式引用父类的dict(并复制它,见上文):

    class Bar(Foo):
        adict = dict(Foo.adict)
        adict.update({'b': 2})
    

    【讨论】:

    • 谢谢 - 这绝对有效 - 希望我能找出一些更通用的东西(例如超级),除了继承之外不涉及显式引用父类。
    • 您在这里并没有真正使用太多继承,因为您使用类字典。你可以只是一个全局字典。效果一样。
    【解决方案2】:

    “我不想在这里使用实例,如果可能的话也不要使用类方法。”

    没错。所以不要。

    foo_adict =  {'a' : 1}
    
    def B():
       foo_adict.update({'b': 2})
    

    我不确定您为什么使用类属性级别字典,它很少以有用或预期的方式表现。

    【讨论】:

    • 类成员他们的用途。诚然,它们是先进的,但它们并不像全局变量那么糟糕,也不等同——你可以(如在我的代码 sn-p 中)每个类有单独的值。我现在正在处理的代码库在一些地方使用类成员,尽管不可否认它是用于繁重的元编程。除了使逻辑分组更加明显之外,classmethods 还必须从某处获取他们处理的数据。
    • 班级成员各有所用。类成员 dictionaries(或其他可变对象)通常不会。
    • 为了提供一些上下文,我正在使用这种组织方法来构建 API。例如,我希望 Foo.adict['a'] 和 Bar.adict['a'] 能够使用不同的值进行初始化,尽管对于大多数变量来说它们是相同的。类定义后字典不会被修改。我还需要 Foo 和 Bar 具有不继承的静态属性。我不明白为什么使用类成员字典本质上是一个坏主意
    • @mlauria:“类定义后字典不会被修改”——在这种情况下,我再次建议您不要将它们作为类实例。特别是因为它是一个 API。对于 API 的用户来说,这是一个令人困惑的 API,他们将开始修改字典,并且它的行为不会像他们预期的那样。选项是全局字典,根本没有字典,而只是直接的类成员,以及某种只读字典。
    【解决方案3】:

    我也遇到了这个问题。我通过使用元类解决了这个问题,它也可以与多重继承一起使用:

    import six
    
    
    class CheckerMeta(type):
    
        def __new__(cls, name, bases, attrs):
            new_class = super(CheckerMeta, cls).__new__(cls, name, bases, attrs)
    
            base_configs = [bc.config for bc in bases if hasattr(bc, 'config')]
            configs = base_configs + [new_class.config]
    
            new_class.config = {}
            for config in configs:
                new_class.config.update(config)
    
            return new_class
    
    
    class BaseChecker(six.with_metaclass(CheckerMeta)):
        config = {}
    
    
    class CheckerA(BaseChecker):
        config = {'a': 1}
    
    
    class CheckerB(BaseChecker):
        config = {'b': 2}
    
    
    class CheckerC(CheckerA, CheckerB):
        config = {'c': 3}
    
    
    assert CheckerA.config == {'a': 1}
    assert CheckerB.config == {'b': 2}
    assert CheckerC.config == {'a': 1, 'b': 2, 'c':3}
    

    【讨论】:

      【解决方案4】:

      Foo 类和Bar 中初始化adict,通过调用initsuper 然后update 进行初始化。

      class Foo(object):
          def __init__(self):
              self.adict = {'a': 1}
      
      
      class Bar(Foo):
          def __init__(self):
              super(Bar, self).__init__()
              self.adict.update({'b': 2})
      

      例子:

      In [14]: b = Bar()
      In [15]: b.adict
      Out[15]: {'a': 1, 'b': 2}
      

      【讨论】:

        猜你喜欢
        • 2014-10-02
        • 1970-01-01
        • 1970-01-01
        • 2017-09-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多