Python:有效更改实例子类(保留原始实例的变量)的最佳方法是什么?



我不是一个非常伟大或经验丰富的Python编码员,我想知道是否有一种简单的方法来做我需要做的事情。但是我还没能自己找到任何东西,因为我不知道如何正确地表达这个问题。

我的情况大致如下:

class Insect:
def __init__(self, arg1):
self.arg1 = arg1
def insect_method(self):
print('do insect stuff')
class Caterpillar(Insect):
def __init__(self, arg1):
super().__init__(arg1)
def caterpillar_method(self):
print('do caterpillar stuff')
class Butterfly(Insect):
def __init__(self, arg1, arg2):
super().__init__(arg1)
self.arg2 = arg2
def butterfly_method(self):
print('do butterfly stuff')

我实际上并没有模拟毛毛虫和蝴蝶,但这是一个类似的过程,所以我认为这可能有助于使事情更清楚。

我有一个超类'Insect',它从来没有被自己创建,但存在,所以子类可以继承它的方法。大多数时候,我只是直接生成子类,就是这样。但是我有一个特殊的情况,Caterpillar子类应该成为Butterfly子类的一个实例。

我已经搜索过了,并且确信改变__class__可能不是我长期想做的事情。然而,我也不确定是否有一种优雅的方式来做到这一点。

目前我能想到的唯一技术是添加一堆if语句,像这样:

class Insect:
def __init__(self, arg1):
self.arg1 = arg1
def insect_method(self):
print('do insect stuff')
class Caterpillar(Insect):
def __init__(self, arg1):
super().__init__(arg1)
def caterpillar_method(self):
print('do caterpillar stuff')
class Butterfly(Insect):
def __init__(self, arg1, arg2, caterpillar=None):
if not caterpillar:
super().__init__(arg1)
else:
self.arg1 = caterpillar.arg1
self.arg2 = arg2
def butterfly_method(self):
print('do butterfly stuff')

如果实际代码像这样简单,这将起作用,但事实并非如此,所以我最终不得不在Butterfly.__init__方法中制作一种Insect.__init__方法的double,然后必须确保在Insect.__init__方法中更改任何内容时不断更新这两个方法。

有没有一种优雅的python方法来实现这种功能,而不需要为Butterfly类创建一个非常复杂的__init__

方法?提前感谢!!

而不是把这个逻辑放在你的__init__,我可能会保持__init__简单,并把逻辑从Caterpillar创建Butterflyclassmethod:

class Butterfly(Insect):
def __init__(self, arg1, arg2):
super().__init__(arg1)
self.arg2 = arg2
@classmethod
def from_caterpillar(cls, caterpillar, arg2):
return cls(caterpillar.arg1, arg2)

那么你可能会有这样的代码:

bob = Caterpillar("Bob")
# metamorphose
bob = Butterfly.from_caterpillar(bob, "Small")

请注意,与原始代码类似,这不会改变原始Caterpillar对象使其成为Butterfly,它创建了一个新的Butterfly实例(并将bob重新分配给它)。

这里有两个不同的概念:蝴蝶是物种,蝴蝶是该物种生活方式的成年阶段。在具有线性类型的纯函数式语言中,您可能有一个函数,它接受一只毛毛虫,产生一只蝴蝶,确保您不能再使用该毛毛虫实例。

在Python中,我可以定义以下类:
from abc import ABC, abstractmethod

class Stage(ABC):
@abstractmethod
def do_something(self):
...

class Caterpillar(Stage):
def do_something(self):
print("do caterpillar stuff")

class AdultButterfly(Stage):
def do_something(self):
print("do butterfly stuff")

class Butterfly(Insect):
def __init__(self):
self.stage = Caterpillar()
def do_something(self):
return self.stage.do_something()
def growup(self):
self.stage = AdultButterfly() 

这允许Butterfly实例从毛毛虫到(成年)蝴蝶的转换,而不需要

  1. 从无到有创造一只成年蝴蝶,或
  2. 从一只毛毛虫产生多只成年蝴蝶

有几种方法可以做到这一点。可能是最易读和"干净"的;(好吧…至少对我来说)是@classmethods:要么通过@Samwise在另一个答案中提出的Butterfly中的from_caterpillar类方法,要么在您的Caterpillar中使用@Pranav Hosangadi在其中一个评论中提出的become_butterfly类方法。

我只是想给你介绍一下isinstance方法。

如果你能让Butterfly的构造函数接受一个"whatever"或者将Caterpillar的实例作为arg1,您可以执行如下操作:

class Butterfly(Insect):
def __init__(self, arg1, arg2):
if isinstance(arg1, Caterpillar):
print("OMG! Metamorphosed!! Digievolution!")
super().__init__(arg1.arg1)
# Or just:
# self.arg1 = arg1. arg1
else:
super().__init__(arg1)
self.arg2 = arg2

最新更新