2017-04-12 75 views
0

this回答它顯示爲屬性傳遞給類__init__Python 2.7:使用setattr設置所有args/kwargs屬性是否很好?

例如,kwargs/ARGS如何自動設置,我們可以這樣做:

class Employee(object): 
    def __init__(self, *initial_data, **kwargs): 
     # EDIT 
     self._allowed_attrs = ['name', 'surname', 'salary', 'address', 'phone', 'mail'] 

     for dictionary in initial_data: 
      for key in dictionary: 
       if key in self._allowed_attrs: # EDIT 
        setattr(self, key, dictionary[key]) 
     for key in kwargs: 
      if key in self._allowed_attrs: # EDIT 
       setattr(self, key, kwargs[key]) 

在我來說,我已經提前知道論點我將通過,所以我正在考慮這個解決方案只有一個較少的重複和較短的代碼。

這是否被認爲是良好做法? 這是針對手動初始化每個屬性的解決方案的贊成/反對?還有其他更好的方法嗎?由於第一條評論/回答(正確)側重於清理參數或列出參數,我認爲在這個框架中可以很容易地解決這個問題。

+1

從[的Python禪](https://www.python.org/dev/peps/pep -0020 /):'顯式優於隱式.'。你需要調用者將'* args'綁定到字典中。 – AChampion

+0

感謝您的評論,但我想我會反對'美麗勝於醜陋'和'可讀性計數'。 25行'self.something = kwargs ['something']'對我來說看起來並不漂亮或不可讀,但這顯然是個人的品味 – FLab

+0

我不同意可讀性,我會指出'稀疏比密集好','難以解釋「等。總的來說,我不會贊成這種做法。 – AChampion

回答

0

之前討論:Python decorator to automatically define __init__ variablesPython: Is it a good idea to dynamically create variables?

優點:

  • 減少代碼重複

缺點:

1

它使我們無法弄清楚該類預期的參數類型。

如果某人(或您在幾個月的時間內)想要在他們的代碼中創建Employee,他們會查看構造函數的參數以查看他們應該傳遞什麼(可能手動或者IDE自動顯示他們)。你的代碼除了隱藏它之外幾乎沒有什麼用處。

0

完全可以使用語言自省功能來減少重複和鍵入你必須做的事情。

當然,這是更好,如果你正在服用注意正確處理的屬性,甚至是消毒的內容 - 所以最好的辦法是要麼爲__init__方法的裝飾,或者它的鹼基相當於類__init__,它將完成所需的任何操作:檢查傳遞的參數對於特定類是否正常,然後使用setattr在實例內設置它們的值。

我認爲不太神奇的方法是在您的類層次結構中有一個約定,以將所需參數聲明爲類屬性。 通過這種方式,您可以使用這些類屬性來記錄預期參數及其類型,並將__init__簽名保留爲*args, **kwargs,並讓您的基類init將其全部處理。

SQLAlchemy Base模型可以做到這一點 - 您可以將類屬性指定爲特殊的「檢測屬性」,並在__init__中調用時自動分配它們。

一個更簡單的方法是:

_sentinel = object() 

class Base(object): 
    def __init__(self, *args, **kwargs): 
     for attr_name, class_attr in self.__class__.__dict__.items(): 
      if isinstance(class_attr, type) and kwargs.get(attr_name, _sentinel) != _sentinel: 
       attr_value = kwargs[attr_name] 
       if not isinstance(attr_value, class_attr): 
        raise TypeError("Parameter {} is expected to be of type {}".format(attr_name, class_attr)) 
       setattr(self, attr_name, attr_value) 


class Person(Base): 
    name = str 
    age = int 
    phonenumber = Phone 
    ... 

這就要求所有的參數以班級爲命名的參數傳遞 - 但他們都將被自動分配給實例的屬性,它會工作,是有稽和安全。如果你想變得更好,只需定義一些奇特的描述符類作爲你的類屬性值。

3

問題:......少重複和更短的代碼

你的示例代碼的需求,9號線和28個關鍵詞

class Employee(object): 
    def __init__(self, name, surname, salary, address, phone, mail): 
     self.name = name 
     self.surname = surename 
     self.salary = salary 
     self.address = address 
     self.phone = phone 
     self.mail = mail 

這個默認的一個需求,6號線和19個關鍵詞。 總結,您的示例需要更多不是「較短的代碼」。 我看不到任何「重複...代碼」在默認的一個,所有的作業完成一次

比較這兩條線,做同樣的事情。控制哪些ARGS可以通過:

self._allowed_attrs = ['name', 'surname', 'salary', 'address', 'phone', 'mail'] 

def __init__(self, name, surname, salary, address, phone, mail): 

第二個需要較少的努力,並做盡在其中。
不需要if key in self._allowed_attrs:,因爲python會爲你做。


在實際項目中,我會用這樣的

class Employee(object): 
    def __init__(self, person, salary=None): 
     self.id = unique_id() 
     self.person = person 
     self.salary = salary 

所有person相關數據都在object person進行了總結。


結論
爲您給出的例子class Employee我永遠不會使用(*args, **kwargs)
(*args, **kwargs)如果無法預測哪些參數已通過,則參數僅有用。

相關問題