2016-01-13 118 views
0

我想自動解包初始化變量一勞永逸。我的思考過程是解壓所有,並使用setattr作爲屬性名稱作爲變量的名稱。如何在python類的init中自動設置自我屬性?

class BaseObject(object): 
    def __init__(self, *args): 
     for arg in args: 
      setattr(self, argname, arg) 

class Sub(BaseObject): 
    def __init__(self, argone, argtwo, argthree, argfour): 
     super(Sub, self).__init__(args*) 

那麼你應該能夠做到:

In [3]: mysubclass = Sub('hi', 'stack', 'overflow', 'peeps') 

In [4]: mysubclass.argtwo 
Out[4]: 'stack' 

基於帕拉姆的 '堆' 已被命名爲argtwo

這樣就可以自動獲得,但你仍然可以覆蓋象下面這樣:

class Sub(BaseObject): 
    def __init__(self, argone, argtwo, argthree, argfour): 
     super(Sub, self).__init__(arglist) 
     clean_arg_three = process_arg_somehow(argthree) 
     self.argthree = clean_arg_three 

顯然我卡在如何傳遞參數(argone,argtwo等)的實際名稱爲一個字符串setattr,以及如何正確地傳遞ARGS到super init(該argssuper(Sub, self).__init__(args*)的)

謝謝

回答

1

BaseObject.__init__()需要以某種方式找到的參數的名稱Sub.__init__()。明確的做法是按照Uri Shalit的建議,將參數字典傳遞給BaseObject.__init__()。或者,你可以使用inspect模塊來神奇地完成這個任務,在你的子類中沒有額外的代碼。這與魔法的通常缺點(「怎麼會發生?」)有關。

import inspect 

class BaseObject(object): 
    def __init__(self): 
     frame = inspect.stack()[1][0] 
     args, _, _, values = inspect.getargvalues(frame) 
     for key in args: 
      setattr(self, key, values[key]) 

class Sub(BaseObject): 
    def __init__(self, argone, argtwo, argthree, argfour): 
     super(Sub, self).__init__() 

書面這工作得很好,但如果你沒有定義Sub.__init__(),這會搶了爭論從錯誤的地方(即,從那裏調用sub()的函數來創建一個對象)。您可能可以使用inspect來重新檢查調用者是BaseObject的子類的__init__()函數。或者,您可以將此代碼移至單獨的方法,例如,set_attributes_from_my_arguments(),並在需要此行爲時從您的子類'__init__()方法中調用該方法。

+0

那是冷血的,沒想到它會變得更好。我會盡量不要如此快速地選擇答案 – codyc4321

+0

你怎麼知道使用那部分堆棧?你只需使用ipdb並檢查inspect.stack()? – codyc4321

+1

幾個月前,我編寫了一個函數來將新變量轉儲到調用者的名稱空間中,我想到了這一點。我想我是通過https://docs.python.org/2/library/inspect.html上的文檔提示進行了試驗和錯誤。最有用的信息是:(1)「[stack()返回]調用者堆棧的幀記錄列表。返回列表中的第一個條目表示調用者;最後一個條目表示堆棧中最外面的調用。因此stack()[1]。(2)「當[stack()返回]'幀記錄時,'每個記錄是一個包含六個元素的元組:幀對象,...」。因此stack()[1] [0]。 –

1

使用kwargs代替ARGS

class BaseObject(object): 
    def __init__(self, **kwargs): 
     for argname, arg in kwargs.iteritems(): 
      setattr(self, argname, arg) 

class Sub(BaseObject): 
    def __init__(self, argone, argtwo, argthree, argfour): 
     super(Sub, self).__init__(argone=argone, argtwo=argtwo, argthree=argthree) 

然後,你可以這樣做:

s = Sub('a', 'b', 'c') 
+0

很乾淨,很有意思。謝謝 – codyc4321

1
import inspect 

class BaseObject(object): 
    def __init__(self, args): 
     del args['self'] 
     self.__dict__.update(args) 

class Sub(BaseObject): 
    def __init__(self, argone, argtwo, argthree, argfour): 
     args = inspect.getargvalues(inspect.currentframe()).locals 
     super(Sub, self).__init__(args) 

s = Sub(1, 2, 3, 4) 
+0

這也很有趣。爲什麼刪除args ['self'],我認爲這只是一個佔位符,它知道它是實例方法? – codyc4321

+1

否則'自己'將被分配。它不會破壞任何東西,但它不是特別有用。嘗試刪除'del args ['self']',你會看到's和'self'會指向同一個對象。 –

+1

'args'條件下的'如果'自我'是不必要的,我將它移除了 –

相關問題