![](/img/trans.png)
[英]Using *args and **kwargs instead of explicitly listing expected parameters
[英]Inheritance best practice : *args, **kwargs or explicitly specifying parameters [closed]
我經常發現自己覆蓋了父 class 的方法,並且永遠無法決定我是應該顯式列出給定參數還是只使用一攬子*args, **kwargs
構造。 一個版本比另一個好嗎? 有最佳實踐嗎? 我缺少什么(不利)優勢?
class Parent(object):
def save(self, commit=True):
# ...
class Explicit(Parent):
def save(self, commit=True):
super(Explicit, self).save(commit=commit)
# more logic
class Blanket(Parent):
def save(self, *args, **kwargs):
super(Blanket, self).save(*args, **kwargs)
# more logic
顯式變體的感知好處
一攬子變體的感知好處
利斯科夫替代原則
通常,您不希望方法簽名在派生類型中有所不同。 如果要交換派生類型的使用,這可能會導致問題。 這通常被稱為Liskov替代原則 。
顯式簽名的好處
與此同時,我認為你的所有方法都不具備*args
, **kwargs
的簽名是正確的。 明確簽名:
可變長度參數和耦合
不要將變長參數誤認為是良好的耦合實踐。 父類和派生類之間應該有一定的內聚力,否則它們就不會彼此相關。 相關代碼導致耦合反映內聚水平是正常的。
使用可變長度參數的位置
使用可變長度參數不應該是您的第一選擇。 當你有充分的理由時應該使用它:
你做錯了什么嗎?
如果您發現自己經常創建帶有許多參數的方法或帶有不同簽名的派生方法,那么您在編寫代碼時可能會遇到更大的問題。
我的選擇是:
class Child(Parent):
def save(self, commit=True, **kwargs):
super(Child, self).save(commit, **kwargs)
# more logic
它避免了從*args
和**kwargs
訪問commit參數,如果Parent:save
的簽名Parent:save
更改(例如添加新的默認參數),它可以保證安全。
更新 :在這種情況下,如果將新的位置參數添加到父級,則使用* args會導致麻煩。 我只保留**kwargs
並僅使用默認值管理新參數。 它可以避免傳播錯誤。
如果你確定Child會保留簽名,那么肯定是明確的方法,但是當Child改變簽名時我個人更喜歡使用這兩種方法:
class Parent(object):
def do_stuff(self, a, b):
# some logic
class Child(Parent):
def do_stuff(self, c, *args, **kwargs):
super(Child, self).do_stuff(*args, **kwargs)
# some logic with c
這樣,簽名中的更改在Child中非常易讀,而原始簽名在Parent中非常易讀。
在我看來,當你有多重繼承時,這也是更好的方法,因為當你沒有args和kwargs時,調用super
幾次是非常惡心的。
對於它的價值,這也是很多Python庫和框架(Django,Tornado,Requests,Markdown等)的首選方式。 雖然不應該根據這些事情做出選擇,但我只是暗示這種做法非常普遍。
不是一個答案,而是一個側面說明:如果你真的,真的想確保父類的默認值傳播到子類,你可以做類似的事情:
class Parent(object):
default_save_commit=True
def save(self, commit=default_save_commit):
# ...
class Derived(Parent):
def save(self, commit=Parent.default_save_commit):
super(Derived, self).save(commit=commit)
但是我不得不承認這看起來很難看,如果我覺得我真的需要它,我只會使用它。
我更喜歡顯式參數,因為自動完成允許您在進行函數調用時查看函數的方法簽名。
除了其他答案:
擁有變量參數可能會將父項與子項“解耦”,但會在創建的對象和父項之間創建耦合,我認為這更糟糕,因為現在你創建了一個“長距離”情侶(更難以發現,更難以維護,因為您可以在應用程序中創建多個對象)
如果您正在尋找脫鈎,請查看合成而不是繼承
為什么沒有人指出 Parent class save() 方法未實現*args and **kwargs
的事實,如果Blanket
的實例嘗試使用更多關鍵字或位置 arguments 調用 save 方法,這將導致錯誤。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.