简体   繁体   English

一种从父类型的对象初始化继承数据类的 pythonic 方法

[英]A pythonic way to init inherited dataclass from an object of parent type

Given a dataclass structure:给定一个数据类结构:

@dataclass
class RichParent:
   many_fields: int = 1
   more_fields: bool = False

class Child(RichParent):
   some_extra: bool = False
   
   def __init__(seed: RichParent):
      # how to init more_fields and more_fields fields here without referencing them directly?
      # self.more_fields = seed.more_fields
      # self.many_fields = seed.many_fields
      pass

What would be the right way to shallow copy seed object fields into the new child object?将种子对象字段浅复制到新的子对象中的正确方法是什么? I wouldn't mind even converting seed to Child type since there is no use for parent object after initialization.我什至不介意将种子转换为子类型,因为初始化后父对象没有用处。

Why do I do that?我为什么要那样做? I want to avoid changing Child class every time RichParent has a change as long as parent stays a plain dataclass.我想避免每次 RichParent 发生更改时更改 Child 类,只要父级保持普通数据类即可。

I am unsure why you'd want to write an explicit __init__ * , although you may need to be on Python 3.10 to be able to pass in fields specific to Child to its init.我不确定你为什么要写一个显式的__init__ * ,尽管你可能需要使用Python 3.10才能将特定于Child的字段传递给它的 init。 **

from dataclasses import dataclass

@dataclass(kw_only=True)
class RichParent:
   many_fields: int = 1
   more_fields: bool = False

#for some reason not setting `@dataclass`` again here means the built in str/repr
#skips the child-only field.
#also if you don't use `kw_only=True` on Child, can't pass in Child only fields
@dataclass(kw_only=True)
class Child(RichParent):
   some_extra: bool = False

seed = RichParent(many_fields=2, more_fields=True)
print(f"\n{seed=}")


child = Child(**vars(seed))
print(f"\n{child=} with {vars(child)=} which does include more_fields")

child2 = Child(**vars(seed),some_extra=True)
print(f"\n{child2=}")


#see the behavior changes in print and field acceptable to constructor
class ChildNoDC(RichParent):
   some_extra: bool = False

child_no_dcdec = ChildNoDC(**vars(seed))
print(f"\n{child_no_dcdec=} with {vars(child_no_dcdec)=} which does include more_fields")



try:
    child_no_dcdec2 = ChildNoDC(some_extra=True,**vars(seed))
except (Exception,) as e: 
    print("\n",e, "as expected")



output:输出:

seed=RichParent(many_fields=2, more_fields=True)

child=Child(many_fields=2, more_fields=True, some_extra=False) with vars(child)={'many_fields': 2, 'more_fields': True, 'some_extra': False} which does include more_fields

child2=Child(many_fields=2, more_fields=True, some_extra=True)

child_no_dcdec=ChildNoDC(many_fields=2, more_fields=True) with vars(child_no_dcdec)={'many_fields': 2, 'more_fields': True} which does include more_fields

 RichParent.__init__() got an unexpected keyword argument 'some_extra' as expected

*

If you did need some custom init on Child, use the builtin post_init hook to do it:如果您确实需要对 Child 进行一些自定义初始化,请使用内置的 post_init 挂钩来执行此操作:

    def __post_init__(self):
        print(f"{self} lets do stuff here besides the std data init...")

From talking about shallow copies, you know about mutability issues, but you could hack some stuff like self.my_dict = self.my_dict.copy() hacks here to work around that.通过谈论浅拷贝,您知道了可变性问题,但是您可以在这里破解一些像self.my_dict = self.my_dict.copy()这样的东西来解决这个问题。

**

as far as I understand, @dataclass does not flip the class into a dataclass type.据我了解,@dataclass 不会将类翻转为数据类类型。 It just builds an __init__ and some methods, (using metaclasses?).它只是构建一个__init__和一些方法(使用元类?)。 So ChildNoDC doesn't know it is dataclass-style class and just tries to pass all fields passed into its constructor call onto Parent 's __init__ .所以ChildNoDC不知道它是数据类样式的类,只是试图将传递到其构造函数调用中的所有字段传递给Parent__init__ Child having been "told" it's dataclassed too, knows better. Child被“告知”它也是数据分类的,知道得更多。 (That's also the reason the child-only field wasn't being printed). (这也是未打印 child-only 字段的原因)。 And kw-only flag frees up some positioning and defaults-only constraints too. kw-only标志也释放了一些定位和默认约束。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何将数据类中的字段类型注释为与其__init__的类型不同? - How to annotate the type of field in dataclass to be different from the type of its __init__? 检查数据类字段是否具有默认值的 Pythonic 方法 - Pythonic way to check if a dataclass field has a default value Python 数据类,验证初始化参数的 Pythonic 方法是什么? - Python dataclass, what's a pythonic way to validate initialization arguments? 在Python中定义具有自动生成的__init__和值字典的附加init2的数据类的正确方法是什么 - What is the proper way in Python to define a dataclass that has both an auto generated __init__ and an additional init2 from a dict of values 从对象继承的类中 super() 和 __init__() 的行为是什么? - What is the behavior of super() and __init__() in class inherited from object? 如何在继承的类中使用主要对象类的__init__? - How to use the __init__ from the main object class in an inherited class? Pythonic(OO) 根据对象类型选择类方法的方式 - Pythonic(OO) way to choose class method depending on the type of object 将类型信息添加到对象属性的pythonic方法是什么? - What is the pythonic way to add type information to an object's attributes? 在 python 数据类 __init__ 方法中强制进行类型转换 - Force type conversion in python dataclass __init__ method 我如何输入提示初始化参数与数据类中的字段相同? - How can i type hint the init params are the same as fields in a dataclass?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM