如何通过Python继承避免重新定义默认参数

leb*_*olo 5 python inheritance constructor default-parameters python-3.x

对于简单的继承,例如

class Base:
  def __init__(self, env: str = 'prod'):
    #...

class Derived(Base):
  def __init__(self, env: str = 'prod'):
    super().__init__(str)
Run Code Online (Sandbox Code Playgroud)

如何避免在两个类中重新定义默认构造函数参数?如果我实例化Derived()我确实想env默认为'prod',我只是不想在多个类中重新定义该值。如果我后来决定默认值应该是其他值(例如'dev'),那么我将不得不更改所有派生构造函数。

我在想类似的事情

class Base:
  def __init__(self, env: str = 'prod'):
    #...

class Derived(Base):
  def __init__(self, env: str = None):
    if env is None:
      super().__init__()
    else:
      super().__init__(env)
Run Code Online (Sandbox Code Playgroud)

或者也许将默认值定义为基类中的全局常量?这两种方法似乎都过于复杂。什么是 Pythonic 方式?

Val*_* B. 2

创建一个类变量。

class Base:
    DEFAULT_ENV = "prod"
    def __init__(self, env=None):
        if env is None:
            env = self.DEFAULT_ENV
        # ...
Run Code Online (Sandbox Code Playgroud)

如果您想在子类中拥有不同的默认环境,只需DEFAULT_ENV在该类中覆盖即可。如果您想更改所有不覆盖它的类的默认环境,则可以进行DEFAULT_ENV更改Base

另外,__init__在 Python 中,在子类中重新定义是可选的,因此如果您不想__init__在子类中实现不同的行为,Base只需在子类中省略它即可。将默认环境变量放在类变量中的另一个优点是,如果您只想更改子类中的默认环境变量,则可以覆盖该类变量,而不必__init__在子类中重新定义!

编辑:如果您觉得 env 确定稍后可能需要一些有趣的业务(例如测试环境变量或应用程序中的其他任何内容),您可能需要包装default_env一个属性:

class Base:
    DEFAULT_ENV = "prod"
    def __init__(self, env=None):
        if env is None:
            env = self.default_env
        # ...
    @property
    def default_env(self):
        return self.DEFAULT_ENV
Run Code Online (Sandbox Code Playgroud)

这样稍后您就可以在属性 getter 中实现预期的行为。