指定对象配置的 Pythonic 方式

Joo*_*ost 3 python constructor

我有一个需要 5 个配置参数的对象,如下所示;

class A(object):

    def __init__(self, a=1, b=2, c=3, d=4, e=4):
        self.a = a
        self.b = b
        self.c = c
        self.d = d
        self.e = e
Run Code Online (Sandbox Code Playgroud)

但是,我想提供几组默认配置,而不仅仅是一组,例如(1, 2, 1, 2, 1)(5, 4, 3, 2, 1),并且最好给它们提供合理的名称。最Pythonic 的方法是什么?我考虑过的一些选项是@classmethod生成实例的选项,或配置实例的实例方法。

jon*_*rpe 5

我将有一个映射到预设配置字典的类方法:

class A(object):

    CONFIGS = {
        'default': {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 4},
        ...
    }

    def __init__(self, a, b, c, d, e):
        ...

    @classmethod
    def from_config(cls, config='default'):
        if config not in cls.CONFIGS:
            raise ValueError('invalid config: {!r}'.format(config))
        return cls(**cls.CONFIGS[config])
Run Code Online (Sandbox Code Playgroud)

然后可以轻松扩展到任意数量的配置,并且可以使用以下方式创建实例:

a = A.from_config(config_name)
Run Code Online (Sandbox Code Playgroud)

您仍然可以为 提供默认参数值__init__,但将它们排除在外意味着如果用户尝试使用A()而不是A.from_config(); ,则会出现错误。这是否是一件好事取决于你,但我认为让用户一致使用或from_config显式自定义参数是有好处的。

子类可以简单地定义自己的CONFIGS字典并使用继承的from_config甚至可能的__init__.


就其他选项而言:

  • 每个预设的单独类方法可以很好地与 IDE 配合使用,但不能很好地扩展或继承(例如,如果子项不支持其父项的预设之一,您该怎么办?);
  • __init__采用参数或配置名称的方法会过于复杂且容易出错;和
  • 如果您需要重新配置实例,配置实例的实例方法可能会很有用,并且可以与我的类方法类似地实现(接口可以是例如a = A().configure(config_name),where configurewill return self),但是类方法更清楚地表明应该设置配置在创建时并且没有改变。

该功能非常简单,您可以将其提取到混合类中以便在其他地方重用:

class Configurable(object):
    """Mix-in for creating instances from preset configs."""

    CONFIGS = {}

    @classmethod
    def from_config(cls, config):
        if config not in cls.CONFIGS:
            raise ValueError('invalid config: {!r}'.format(config))
        args, kwargs = cls.CONFIGS[config]
        return cls(*args, **kwargs)


class A(Configurable, ...):  # can still include any other inheritance

    CONFIGS = {
        'default': ((), {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 4}),
        ...
    }

    def __init__(self, a, b, c, d, e):
        ...

    @classmethod
    def from_config(cls, config='default'):
        return super(A, cls).from_config(config)
Run Code Online (Sandbox Code Playgroud)

请注意,为了尽可能广泛地重用,我现在单独提供了positionalargs和named kwargs,并删除了default config