在子类中扩展类属性的简洁方法

16 投票
6 回答
3523 浏览
提问于 2025-04-15 11:49

假设我有一个这样的类

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

还有一个叫做 Child 的子类

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

我想在子类中能够重写或者添加一些选项。我现在用的方法是有效的,但我觉得一定有更好的办法。


补充说明

我不想把选项作为类的属性添加,因为我还有其他的类属性不是选项,我更希望把所有的选项放在一个地方。这只是一个简单的例子,实际上代码要复杂得多。

6 个回答

6

经过进一步思考,再加上@SpliFF的建议,我想出了这个方案:

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


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

不过我还是欢迎更好的解决办法。

21

这段代码在功能上和你的代码是一样的,但看起来更整洁:

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

记住,“生活没有大括号更美好”,通过明确调用 dict,你通常可以避免使用大括号(还有那些围绕常量字符串的额外引号)。

想了解更多细节,可以查看这个链接:http://docs.python.org/library/stdtypes.html#dict。关键点是:“如果一个键同时在位置参数和关键字参数中被指定,那么关键字参数对应的值会被保留”,也就是说,关键字参数会覆盖位置参数中的键值对,就像 update 方法可以让你覆盖它们一样。

8

一种方法是使用关键字参数来给字典添加额外的键:

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

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

如果你想让事情更复杂一点,可以使用描述符协议来创建一个代理对象,这样可以封装查找的过程。具体来说,就是从拥有者的属性开始,沿着拥有者的__mro__(方法解析顺序)走到__get__(self, instance, owner)这个方法。更复杂的做法是使用 metaclasses(元类)或者类装饰器,但这可能不是个好主意。

撰写回答