2016-11-30 76 views
3

我有一個類與許多實例變量與默認值,可以選擇可以在實例化(注意:沒有可變的默認參數)重寫。Python:程序類實例變量初始化與本地人()

因爲編寫self.x = x等很多次都是相當多餘的,所以我以編程方式初始化變量。

爲了說明,考慮本實施例中(其具有,爲了簡潔起見,僅5中省略實例變量和任何方法):

實施例:

# The "painful" way 
class A: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
     self.a = a 
     self.b = b 
     self.c = c 
     self.d = d 
     self.e = e 

# The "lazy" way 
class B: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
     self.__dict__.update({k: v for k, v in locals().items() if k!='self'}) 

# The "better lazy" way suggested 
class C: 
    def __init__(self, a, b=2, c=3, d=4.5, e=5): 
      for k, v in locals().items(): 
       if k != 'self': 
        setattr(self, k, v) 

x = A(1, c=7) 
y = B(1, c=7) 
z = C(1, c=7) 

print(x.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 
print(y.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 
print(z.__dict__) # {'d': 4.5, 'c': 7, 'a': 1, 'b': 2, 'e': 5} 

因此,爲了使我的生活更容易,我使用B類中所示的成語,其結果與A相同。

這是不好的做法嗎?有沒有什麼陷阱?

附錄: 另一個理由使用這個成語是爲了節省一些空間 - 我打算MicroPython使用它。 無論出於何種原因Because locals work differently there,只有類A中顯示的方式工作。

+1

是的。這是不好的做法。爲什麼不使用'dict()'?他們必須是班級屬性嗎? –

+4

相關:http://stackoverflow.com/q/1389180/3001761。 – jonrsharpe

+2

我想不出任何明顯的缺陷,但我確實發現它很糟糕。 – wim

回答

3

我實際上會建議使用class A中顯示的代碼。你有什麼是重複代碼,不是冗餘代碼,重複不是總是不好。你只需要編寫__init__一次,並保持每個實例變量的一個賦值就是你的類期望的實例變量的良好文檔(明確和清晰)。

但有一點要記住的是,許多變量,您可以初始化爲不同的參數可能是您的類需要重新設計的跡象。將某些單獨的參數更合理地分組到單獨的列表,字典或甚至其他類中嗎?

+1

Alex Martelli說了一些[應該在stdlib](http://stackoverflow.com/questions/1389180/python-automatically-initialize-instance-variables#comment1230512_1389224)到避免這種重複。然而,7年後,什麼也沒有。所以......¯\\ _(ツ)_ /¯....在這裏,有一個+1。 – wim

1

嘗試一個更Python的方法:

class C: 
    def __init__(self,a,b=2,c=3,d=4.5,e=5): 
    for k,v in locals().iteritems(): 
     setattr(self,k,v) 
c = C(1) 
print c.a, c.b 
1 2 

這種方法可能是一兩行更長的時間,但線路長度短,你的意圖少令人費解。另外,任何可能試圖重用代碼的人都可以按照預期訪問對象的屬性。

希望這會有所幫助。

編輯:刪除第二種方法使用kwargs bc它沒有解決默認變量的要求。

的重要外賣這裏是你的代碼的用戶將無法訪問您的對象的屬性如預期,如果做喜歡你的例子B類節目。

+0

'kwargs'在這種情況下沒有用處:它不保證所有需要的變量都被傳入,並且不需要的變量可以作爲實例變量傳入並存儲。 – phoibos

+3

你的第二種方法不允許默認值,這在問題中顯然是需要的。在你的第一種方法中,從迭代中排除'self' – donkopotamus

+0

好點,如果需要默認值,則使用第一種方法。 @donkopotamus:setattr需要3個參數。第一個需要是對象的一個​​實例。如果在類定義中操作,則此實例必須是自己的。 –