[英]python - Accessing superclass's class attribute in super().__init__()
我有一個具有許多實例屬性的Parent
類,我總是傳遞一個dict
來初始化一個實例。 像這樣:
info = {
"name" : "Bob",
"col" : 5,
"line" : 10,
"type" : "Alien"
}
p = Parent(info)
在__init__
方法中,我不想為每個屬性編寫this.property_name = value
因為代碼會很長。 例如:
class Parent(object):
def __init__(self, kwargs):
this.name = kwargs.get("name")
this.col = kwargs.get("col")
this.line = kwargs.get("line")
this.type = kwargs.get("type")
所以我想用一個函數來迭代dict
來設置這些實例屬性。 這是我寫的函數:
def initialize_properties(instance, names, kwargs):
for name in names:
setattr(instance, name, kwargs.get(name))
似乎我需要將屬性名稱列表names
存儲在某處,我決定將其存儲為類屬性,因為我希望我的類對人類友好(當有人閱讀類定義時,他知道該類具有哪些實例屬性) . 所以我改變了我的類定義如下:
class Parent(object):
props = ("name", "col", "line", "type")
def __init__(self, kwargs):
initialize_properties(self, self.props, kwargs)
當不考慮繼承時,這很好用。 當我對Parent
子類化時會出現問題:
class Child(Parent):
props = ("foo", "bar")
def __init__(self, kwargs):
super().__init__(kwargs)
initialize_properties(self, self.props, kwargs)
我希望Child
的實例繼承超類Parent
所有實例屬性,以及一些特定於孩子的實例屬性。(這就是我們使用繼承的原因,不是嗎?)所以我覆蓋了類屬性props
來定義 child-具體屬性。
但它不起作用。
info = {
"name" : "Bob",
"col" : 5,
"line" : 10,
"type" : "Alien",
"foo" : 5,
"bar" : 10
}
c = Child(info)
實例c
只有c.foo
和c.bar
定義和設置,而c.name
沒有定義。
經過一番挖掘,我發現當通過super()
函數調用Parent.__init__(self, kwargs)
,傳遞的self
參數是Child
類,因此self.props
評估為Child.props
。
如果我想在Parent.props
設置實例屬性,我必須在Parent.__init__(self, kwargs)
顯式使用Parent.props
,即:
class Parent(object):
props = ("name", "col", "line", "type")
def __init__(self, kwargs):
initialize_properties(self, Parent.props, kwargs)
這將解決問題,但我認為它不是很“干凈”,因為您必須對類名Parent
進行硬編碼。
所以我的問題是:當您調用super().__init__()
鏈來初始化子類實例時,有沒有辦法檢測當前類並訪問其類屬性?
您可以實現一個從所有超類收集props
並在__init__
使用它的方法:
class Parent(object):
props = ("name", "col", "line", "type")
def __init__(self, **kwargs):
def __init__(self, kwargs):
initialize_properties(self, self.get_props(), kwargs)
def get_props(self):
return sum((getattr(k, 'props', ()) for k in self.__class__.mro()), ())
現在,您可以按照您想要的方式簡單地定義子類。 您甚至不必覆蓋構造函數:
class Child(Parent):
props = ("foo", "bar")
話雖如此,您聲稱您希望您的課程對人類友好。 如果有人閱讀您的孩子課程,他們會很高興閱讀:
class Child(Parent):
props = 'foo', 'bar', 'name', 'col', 'line', 'type'
並將所有班級的props
集中在一處。
self.props
首先引用實例屬性,然后是類屬性,以及父類的類屬性,...
通過定義Child.props
, self.props
引用Child.props
類屬性,停在那里,而不是在父類中搜索。
如何讓Child.props
也包括父母的props
?
class Child(Parent):
props = Parent.props + ("foo", "bar") # <---
def __init__(self, kwargs):
super().__init__(kwargs)
initialize_properties(self, self.props, kwargs)
回答你的問題
當您調用 super() 鏈時,有什么方法可以檢測當前類並訪問其類屬性。 初始化()
在我看來,沒辦法。
但是,您可以使用裝飾器來簡化您的代碼
def add_props(names, cls=None):
if cls is None:
return lambda cls:add(names, cls)
for c in cls.__bases__:
names.extend(c.props)
names = list(set(names))
cls.props = names
return cls
class A:
props = ['a','b']
@add_props(names=['c'])
class B(A):
pass
輸出:
In [69]: B.props
Out[69]: ['a', 'b', 'c']
但是,必須說,如果你想要人性化,我認為最好的方法是不使用props
,只需在你的__init__
方法中編寫代碼。
class Root:
def __init__(self, a=None, b=None):
self.a = a
self.b = b
class Child(Root):
def __init__(self, c=None, d=None, **kwargs):
self.c = c
self.d = d
super().__init__(**kwargs)
您也可以方便地根據需要傳遞 dict
data = {'a': 1}
c = Child(**data)
它不僅對人類友好,而且對大多數編輯也友好。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.