【问题标题】:Passing args and kwargs to base python object将 args 和 kwargs 传递给基础 python 对象
【发布时间】:2022-01-06 11:04:57
【问题描述】:

我有一些需要编组的数据,其中有两种具有一些基本行为的主要类型。为了避免实际上封送数据的所有重复逻辑,我决定使用继承。我认为对象也是一个不错的选择,因为我可以添加类型提示,并使所有参数都成为必需的(比如 dict,这是我们目前使用的,容易出现拼写错误/字段遗漏)。 我也知道TypedDict,但由于有一点点与数据相关的行为,我觉得这不是一个好的选择。 dataclass 似乎是一个很好的中间立场,只是它在继承方面不是很好,并且暴露了一些应该对调用者隐藏的字段。 我真正关心的是强制执行所需的参数和类型。

假设我有这些课程

class Base:
    def __init__(self, id: str, **kwargs):
        self.id = id # the caller doesn't need to know about this field.
        # data really just needs to be collected into this dict with arg names as keys
        self.properties = kwargs or {}


class A(Base):
    def __init__(self, a: str, b: str, c: datetime):
        super().__init__(foo_id, a=a, b=b, c=c)

当有三个参数时这很好,但有些参数有十个,而且只有大量的样板。有没有办法删除所有传递给Base 的arg,或者甚至只是将args 收集到kwargs 中并将其传递下去?

【问题讨论】:

  • 这似乎倒退了。通常的建议是,每个类都定义他们期望的特定参数,并接受将传递给super().__init__ 的任意关键字参数,假设 somebody 上游想要它们。
  • 问题是,谁需要abcABase?如果A,它应该只是将它们添加到self.properties 本身。 (dict 保证在super().__init__ 返回后存在。)

标签: python inheritance keyword-argument python-dataclasses


【解决方案1】:

您可以使用默认方法在 python 中传递所有参数:


class A(Base):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)

这是标准的 python 来捕获然后传递所有参数。

但是,给您一个单独的问题:您是否需要定义自己的初始化处理步骤?

...在上面的示例中,您的子类的 init 除了调用父类的 init 之外没有做任何事情。

如果您在子类中定义__init__ 方法,则在创建实例时python 将自动调用父类中的__init__所以你不需要在任何地方定义init除非你需要为某些类特定的步骤

例如:

class Base: 
    def __init__(self, arg1 = "argument one"): 
        self.arg1 = arg1 
     
         
class Derived(Base): 
    pass 
     
b = Base() 
print b.arg1 
 
d = Derived() 
print d.arg1 

# output:
argument one 
argument one 

【讨论】:

    【解决方案2】:

    一个类应该提取它期望的关键字参数,并将其余的传递给上游,假设 somebody 需要它们。调用者有责任传递所有必需的参数。

    class Base:
        def __init__(self, *, id: str, **kwargs):
            super.__init__(**kwargs)
            self.id = id
            self.properties = {}
    
    class A(Base):
        def __init__(self, *, a: str, b: str, c: datetime, **kwargs):
            super().__init__(**kwargs)
            # self.properties is guaranteed to exist at this point
            self.properties['a'] = a
            self.properties['b'] = b
            self.properties['c'] = c
    
    a = A(id=foo_id, a="baz", b="bar", c=datetime.datetime.now())
    

    如果您真的希望 A.__init__foo_id 硬编码为 Baseid 属性,您可以:

    class A(Base):
        def __init__(self, *, a: str, b: str, c: datetime, **kwargs):
            super().__init__(id=foo_id, **kwargs)
            self.properties['a'] = a
            self.properties['b'] = b
            self.properties['c'] = c
    
    a = A(a="baz", b="bar", c=datetime.datetime.now())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-26
      • 1970-01-01
      • 2015-01-28
      • 2020-09-16
      • 2017-01-28
      • 1970-01-01
      相关资源
      最近更新 更多