gpt4 book ai didi

python - 扩展卡住数据类并从基类实例中获取所有数据

转载 作者:行者123 更新时间:2023-12-03 23:06:35 25 4
gpt4 key购买 nike

假设我们有一个来自图书馆的类,

@dataclass(frozen=True)
class Dog:
name: str
blabla : int
# lot of parameters
# ...
whatever: InitVar[Sequence[str]]

我有一个来自外部库的狗构造函数。
pluto = dog_factory() # returns a Dog object

我希望这只狗有一个新成员,比如说' bite '。
显然 pluto['bite'] = True将失败,因为数据类被卡住。

所以我的想法是从 Dog 创建一个子类并从“pluto”实例中获取所有数据。
class AngryDog(Dog):
# what will come here ?

有没有办法避免手动将所有类 Dog 参数放入 初始化 ?
类似于复制构造函数的东西。

理想情况下:
class AngryDog(Dog):
def __init__(self, dog, bite = True):
copy_construct(dog)

最佳答案

如果你想使用继承来解决你的问题,你需要从写一个正确的 AngryDog 开始。可用于从中构建健全实例的子类。

下一步是添加 from_dog classmethod ,可能是这样的:

from dataclasses import dataclass, asdict

@dataclass(frozen=True)
class AngryDog(Dog):
bite: bool = True

@classmethod
def from_dog(cls, dog: Dog, **kwargs):
return cls(**asdict(dog), **kwargs)

但是按照这种模式,您将面临一个特定的极端情况,您自己已经通过 whatever 指出了这一点。范围。当重新调用 Dog构造函数,任意 InitVar将在 asdict 中丢失调用,因为它们不是该类的正确成员。事实上,数据类中发生的任何事情' __post_init__ ,这是 InitVars去,可能会导致错误或意外行为。

如果它只是像过滤或删除 cls 中的已知参数这样的小事调用并且父类预计不会改变,您可以尝试在 from_dog中处理它.但从概念上讲,没有办法为这种 from_instance 提供通用解决方案。问题。

Composition从数据完整性的角度来看,它可以无错误地工作,但考虑到手头的确切问题,它可能是单调的或笨拙的。这样的 dog-extension 不能代替适当的 dog-instance 使用,但如果有必要,我们可以将其鸭型化成正确的形状:

class AngryDogExtension:
def __init__(self, dog, bite=True):
self.dog = dog
self.bite = bite

def __getattr__(self, item):
"""Will make instances of this class bark like a dog."""
return getattr(self.dog, item)

用法:

# starting with a basic dog instance
>>> dog = Dog(name='pluto', blabla=1, whatever=['a', 'b'])

>>> dog_e = AngryDogExtension(d)
>>> dog_e.bite # no surprise here, just a regular member
True
>>> dog_e.name # this class proxies its dog member, so no need to run `dog_e.dog.name`
pluto

但最终,重点仍然是 isinstance(dog_e, Dog)将返回 False .如果您 promise 调用电话返回 True ,有一些高级技巧可以帮助您,并使任何继承您的代码的人讨厌您:

class AngryDogDoppelganger(Dog):
def __init__(self, bite, **kwargs):
if "__dog" in kwargs:
object.__setattr__(self, "__dog", kwargs["__dog"])
else:
object.__setattr__(self, "__dog", Dog(**kwargs))
object.__setattr__(self, "bite", bite)

@classmethod
def from_dog(cls, dog, bite=True):
return cls(bite, __dog=dog)

def __getattribute__(self, name):
"""Will make instances of this class bark like a dog.

Can't use __getattr__, since it will see its own instance
attributes. To have __dog work as a proxy, it needs to be
checked before basic attribute lookup.
"""
try:
return getattr(object.__getattribute__(self, "__dog"), name)
except AttributeError:
pass
return object.__getattribute__(self, name)

用法:

# starting with a basic dog instance
>>> dog = Dog(name='pluto', blabla=1, whatever=['a', 'b'])

# the doppelganger offers a from_instance method, as well as
# a constructor that works as expected of a subclass
>>> angry_1 = AngryDogDoppelganger.from_dog(dog)
>>> angry_2 = AngryDogDoppelganger(name='pluto', blabla=1, whatever=['a', 'b'], bite=True)

# instances also bark like at dog, and now even think they're a dog
>>> angry_1.bite # from subclass
True
>>> angry_1.name # looks like inherited from parent class, is actually proxied from __dog
pluto
>>> isinstance(angry_1, Dog) # 🎉
True

大多数添加数据类的方法,如 __repr__ , 但是会被破坏,包括在 dataclass.asdict 之类的东西中插入分身实例甚至只是 vars - 所以使用风险自负。

关于python - 扩展卡住数据类并从基类实例中获取所有数据,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62322620/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com