在写 Python 代码的时候,大家可能会在不知不觉中使用一些设计范式。我们来看两个例子。
假设有一个类People
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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
:
1 2 3 4 5 6 7
| 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
方法。
这个过程看起来似乎没有什么问题,相信很多读者也是这样写代码的。
现在,我们再增加两个类:
1 2 3 4 5 6 7
| class Restaurant: def __init__(self, name): self.name = name self.consumer = People('张三', 30, '男') def start_launch(self): self.consumer.eat()
|
1 2 3 4 5 6 7
| class Ballroom: def __init__(self, address): self.address = address self.dancer = People('小红', 20, '女') def open(self): self.dancer.dance()
|
新增加的两个类Restaurant
和Ballroom
的构造函数里面都通过People
类初始化了对象。然后在调用这个对象的方法。
这样写看起来没有问题,能正常工作,代码也不丑。
现在,People
类需要修改一下它的构造函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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
改成默认参数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| 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
初始化以后的对象传到其他类的构造函数中即可:
1 2 3 4 5 6 7 8 9 10 11
| 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()
|
虽然叫做编程范式,但也不是说应该始终使用依赖注入。例如你的代码会层层调用,难道从第一层把对象一层一层传到最里面去?所以应该根据实际情况来进行选择。