我正在嘗試找到一種在類方法中回傳(新)類物件的好方法,該類物件也可以擴展。
我有一個類(classA),它具有其他方法,一個在一些處理后回傳一個新的classA物件的方法
class classA:
def __init__(): ...
def methodX(self, **kwargs):
process data
return classA(new params)
現在,我將這個類擴展到另一個類 B。我需要methodX做同樣的事情,但這次回傳classB,而不是classA
class classB(classA):
def __init__(self, params):
super().__init__(params)
self.newParams = XYZ
def methodX(self, **kwargs):
???
這可能是微不足道的,但我根本無法弄清楚。最后,我不想每次擴展類時都重寫 methodX。
感謝您的時間。
uj5u.com熱心網友回復:
像這樣使用__class__屬性:
class A:
def __init__(self, **kwargs):
self.kwargs = kwargs
def methodX(self, **kwargs):
#do stuff with kwargs
return self.__class__(**kwargs)
def __repr__(self):
return f'{self.__class__}({self.kwargs})'
class B(A):
pass
a = A(foo='bar')
ax = a.methodX(gee='whiz')
b = B(yee='haw')
bx = b.methodX(cool='beans')
print(a)
print(ax)
print(b)
print(bx)
uj5u.com熱心網友回復:
class classA:
def __init__(self, x):
self.x = x
def createNew(self, y):
t = type(self)
return t(y)
class classB(classA):
def __init__(self, params):
super().__init__(params)
a = classA(1)
newA = a.createNew(2)
b = classB(1)
newB = b.createNew(2)
print(type(newB))
# <class '__main__.classB'>
uj5u.com熱心網友回復:
我想提出我認為最干凈的方法,盡管類似于現有的答案。這個問題感覺很適合類方法:
class A:
@classmethod
def method_x(cls, **kwargs):
return cls(<init params>)
使用@classmethod裝飾器可確保第一個輸入(傳統上稱為cls)將參考方法所屬的類,而不是實體。
(通常我們稱第一個方法輸入self,this指的是方法所屬的實體)
因為cls是指A,而不是A 的一個實體,所以我們可以像呼叫cls()一樣呼叫A()。
但是,在繼承自的類中A,cls將根據需要參考子類:
class A:
def __init__(self, x):
self.x = x
@classmethod
def make_new(cls, **kwargs):
y = kwargs["y"]
return cls(y) # returns A(y) here
class B(A):
def __init__(self, x):
super().__init__(x)
self.z = 3 * x
inst = B(1).make_new(y=7)
print(inst.x, inst.z)
現在您可以預期該 print 陳述句會生成7 21.
存在應該inst.z為您確認該make_new呼叫(僅在 A 上定義并由 B 未更改地繼承)確實創建了 B 的實體。
但是,有一點我必須指出。繼承未更改的make_new方法僅有效,因為__init__B 上的方法與 A 上的方法具有相同的呼叫簽名。如果不是這種情況,則cls可能必須更改對的呼叫。
這可以通過允許方法并**kwargs在父類中__init__傳遞泛型**kwargs來規避:cls()
class A:
def __init__(self, **kwargs):
self.x = kwargs["x"]
@classmethod
def make_new(cls, **kwargs):
return cls(**kwargs)
class B(A):
def __init__(self, x, w):
super().__init__(x=x)
self.w = w
inst = B(1,2).make_new(x="spam", w="spam")
print(inst.x, inst.w)
在這里,我們能夠給 B 一個不同的(更嚴格的!)簽名。
這說明了一個一般原則,即父類通常比它們的子類更抽象/更不具體。
因此,如果您想要兩個基本共享行為但做完全不同的事情的類,最好創建三個類:一個相當抽象的類,它定義了共同行為,兩個子類為您提供你想要的特定行為。
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/459971.html
上一篇:Haskell子類化和實體重疊
下一篇:在Ruby中使用委托維護相同的類
