As @ Jan-PhilipGehrcke指出,pythonic
可能難以量化。對我來說,它意味着:
- 容易閱讀
- 易於維護
- 簡單比複雜好是比複雜
- 等等,等等,等等(見
Zen of Python
完整列表更好,在解釋器中輸入import this
)
所以,最pythonic的解決方案取決於你必須爲每個支持的初始化器做什麼,以及它們中有多少喲你有。我會說,如果你有隻有極少數,而且每一個可以只按幾行代碼進行處理,然後用isinstance
和__init__
:
class MyClass(object):
def __init__(self, initializer):
"""
initialize internal data structures with 'initializer'
"""
if isinstance(initializer, dict):
for k, v in itit_dict.items():
# do something with k & v
setattr(self, k, v)
elif isinstance(initializer, (list, tuple)):
for item in initializer:
setattr(self, item, None)
在另一方面,如果你有很多可能的初始化,或如果其中任何一個需要大量的代碼來處理,那麼你會想爲每一個可能的init類型的一個classmethod
構造,在__init__
最常見的用法是:
class MyClass(object):
def __init__(self, init_dict={}):
"""
initialize internal data structures with 'init_dict'
"""
for k, v in itit_dict.items():
# do something with k & v
setattr(self, k, v)
@classmethod
def from_sequence(cls, init_list):
"""
initialize internal data structures with 'init_list'
"""
result = cls()
for item in init_list:
setattr(result, item, None)
return result
這樣可以使每一個可能的構造簡單,乾淨,易於理解。作爲一個方面說明:使用可變對象作爲默認值(就像我在上面的__init__
中所做的那樣)需要小心完成;原因是默認值只被評估一次,然後無論結果是什麼,將被用於之後的每個調用。當你在你的函數中修改這個對象時,這只是一個問題,因爲這些修改會在每次後續調用中看到 - 除非你想創建一個可能不是你想要的行爲的緩存。這對我的例子來說不是問題,因爲我沒有修改init_dict
,只是迭代它(如果調用者沒有替換它,因爲它是空的,這是沒有操作的)。
爲什麼不使用'* args'和'** kwargs'? – 2013-03-15 13:59:21
用戶類方法作爲備用構造函數。看到我這個類似的問題:http://stackoverflow.com/questions/682504/what-is-a-clean-pythonic-way-to-have-multiple-constructors-in-python/682545#682545 – Ber 2013-03-15 14:32:01
另外,不要在功能或方法中使用「{}」作爲默認參數。爲了說明它在一些情況下,它表現爲一個「C靜態」變量 - 每個函數調用將看到與先前調用相同的對象。 – jsbueno 2013-03-15 14:37:30