­

一日一技:為什麼年代久遠的 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()  

新增加的兩個類RestaurantBallroom的構造函數裏面都通過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參數。現在怎麼辦?

於是ClassRoomRestaurantBallroom這三個類的構造函數都要隨之做修改,全都得加上這個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()  

雖然叫做編程範式,但也不是說應該始終使用依賴注入。例如你的代碼會層層調用,難道從第一層把對象一層一層傳到最裏面去?所以應該根據實際情況來進行選擇。