簡體   English   中英

使用繼承,實例化,* args,** kwargs的代碼混亂

[英]Confusion in code using inheritance, instantiation, *args, **kwargs

class Pen(object):
    def __init__(self, mean_radius = None, length = None):
        self.usage = "Is used to apply ink trails to drawing surfaces"
        self.mean_radius = mean_radius
        self.length = length

class FountainPen(Pen):
    def __init__(self, manufacturer = "Waterman", *args, **kwargs):
        Pen.__init__(self, *args, **kwargs)
        self.manufacturer = manufacturer
        self.cartridge_state =  "non-empty"

>>> instance_FP = FountainPen(5, 1)
>>> instance_FP.mean_radius
>>> print instance_FP.mean_radius
1    
>>> print instance_FP.length
None

FountainPen的實例化中將整數5作為參數傳遞時會發生什么情況? 為什么print instance_FP.mean_radius返回1而不是5

您必須這樣認為: *args**kwargs “吃掉”在它們前面的“常規”參數留下的所有位置/關鍵字參數。 如果把它們放在最后,它們只會得到不適合“常規參數”的任何東西。

因此,當您編寫FountainPen(5,1) ,會發生FountainPen.__init__調用FountainPen.__init__情況:

  • self設置為新創建的實例;
  • manufacturer獲得第一個參數,即5;
  • *args “吃掉”所有剩余的位置參數,即僅1 因此args現在設置為[1]
  • *kwargs會吃掉剩下的所有關鍵字參數,但是沒有關鍵字,因此它變成{}

然后很明顯, Pen.__init__ 1作為參數(除了self )調用了Pen.__init__ ,而length仍設置為其默認值( None )。

Matteo Italia的提法出了什么問題,基本上manufacturer是一個立場論點。 您可以通過將FountainPen__init__稍微更改為以下內容來修復它:

def __init__(self, *args, manufacturer = "Waterman", **kwargs):

這樣做會使manufacturer成為關鍵字參數,因此要更改它,您必須調用:

FountainPen(manufacturer="newval")

注意:不幸的是,這種語法(在*args參數后僅具有關鍵字參數)僅在Python 3中有效。Jon Clements的解決方案可解決Python 2的此問題。

一個更優雅的解決方案是:

class FountainPen(Pen):
    def __init__(self, *args, **kwargs):
        Pen.__init__(self, *args, **kwargs)
        self.manufacturer = kwargs.get('manufacturer', 'Waterman')
        self.cartridge_state =  "non-empty"

blah = FountainPen(5, 1, manufacturer='Waterman')

在您的代碼中,將5分配給參數manufacturer ,將1分配給*args

將不帶鍵的參數傳遞給函數時,必須首先提供顯式參數。 其余的傳遞給* args。 為避免這種情況,請在調用構造函數時提供關鍵字:

>>> instance_FP = FountainPen(mean_radius=5, length=1)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM