一日一技:為什麼年代久遠的 Python 項目裏面那麼多默認參數?
- 2020 年 2 月 11 日
- 筆記

攝影:產品經理
蠟燭上面的跑馬燈
在寫 Python 代碼的時候,大家可能會在不知不覺中使用一些設計範式。我們來看兩個例子。
假設有一個類People
:
class People: def __init__(self, name, age, sex): self.name = name self.age = age self.sex = sex def dance(self): print('我在跳舞') def study(self): print('我在學習') def eat(self): print('我在吃東西')
現在我們有另一個類ClassRoom
:
class ClassRoom: def __init__(self, size): self.size = size self.student = People('小明', 17, '男') def start_class(self): self.student.study()
我們在ClassRoom
的構造函數中,初始化了一個 student 對象,然後在start_class
方法中,調用了這個對象的study
方法。
這個過程看起來似乎沒有什麼問題,相信很多讀者也是這樣寫代碼的。
現在,我們再增加兩個類:
class Restaurant: def __init__(self, name): self.name = name self.consumer = People('張三', 30, '男') def start_launch(self): self.consumer.eat()
class Ballroom: def __init__(self, address): self.address = address self.dancer = People('小紅', 20, '女') def open(self): self.dancer.dance()
新增加的兩個類Restaurant
和Ballroom
的構造函數裏面都通過People
類初始化了對象。然後在調用這個對象的方法。
這樣寫看起來沒有問題,能正常工作,代碼也不醜。
現在,People
類需要修改一下它的構造函數:
class People: def __init__(self, name, age, sex, address): self.name = name self.age = age self.sex = sex def dance(self): print('我在跳舞') def study(self): print('我在學習') def eat(self): print('我在吃東西')
在初始化People
類時,需要傳入一個address
參數。現在怎麼辦?
於是ClassRoom
、Restaurant
、Ballroom
這三個類的構造函數都要隨之做修改,全都得加上這個address
參數。
這就叫做牽一髮而動全身
。
很多人為了避免做這樣的修改,會把新增加的這個參數address
改成默認參數:
class People: def __init__(self, name, age, sex, address=''): self.name = name self.age = age self.sex = sex def dance(self): print('我在跳舞') def study(self): print('我在學習') def eat(self): print('我在吃東西')
這樣看起來,另外三個類的代碼就不需要做任何修改了。
這就是為什麼你們公司的代碼裏面,很多函數會帶上大量奇奇怪怪的默認參數的原因。 」
在編程範式中,有一個術語叫做依賴注入
,就是為了解決這個問題的。
而且做起來簡單到你覺得這是在逗你,把People
初始化以後的對象傳到其他類的構造函數中即可:
class Ballroom: def __init__(self, address, dancer): self.address = address self.dancer = dancer def open(self): self.dancer.dance() dancer = People('小紅', 20, '女') ballroom = Ballroom('xxx', dancer) ballroom.open()
雖然叫做編程範式,但也不是說應該始終使用依賴注入。例如你的代碼會層層調用,難道從第一層把對象一層一層傳到最裏面去?所以應該根據實際情況來進行選擇。