3.3.2 子类无法使用父类的私有属性和方法

通过继承,能把通用性的代码放在父类。不过在使用时,往往会有一种错误的做法:把父类里所有的方法和属性都定义成公有的,这样在子类里调用起来也方便。

在如下的InheritanceBadUsage.py案例中,我们来看一下这种任意扩大父类方法可见性的错误做法可能会带来的问题。


01 # coding=utf-8
02 class Emp:
03     def __init__(self, name,salary):
04         self.name = name
05         self.salary=salary
06     def addSalary(self, number):
07         self.getApproval()
08         self.salary = self.salary + number
09     # def __getApproval(self):# 正确的做法
10     def getApproval(self):# 错误的做法
11          print('Before addSalary, get Approval.')
12 class PythonDeveloper(Emp):
13     def learnPython(self):
14         print(self.name + ' learn Python.')
15 pythonDev = PythonDeveloper('Peter',12000)
16 pythonDev.getApproval() # 不应当向子类开放getApproval的权限
17 pythonDev.addSalary(5000)

在第6行父类定义的addSalary方法里,出于逻辑上的考虑,在给员工加工资前,应当首先获得老板的批准,而这个动作属于实现细节,应当向外界屏蔽,否则任何子类都可以通过调用这个方法擅自给自己加工资。

从这个逻辑意义上来讲,第10行定义的getApproval的做法是错误的,因为该方法被定义成公有的,从第16行的语句来看,这样定义的话Emp的子类PythonDeveloper也能调用该方法。事实上不该让其他子类调用。所以应当如第9行那样,把该方法设计成私有的。

从语法上讲,子类无法访问父类中的私有属性和方法,比如一旦打开第9行的注释,同时注释掉第10行的代码,第16行的代码就会出错。不过在使用面向对象思想开发Python项目时,更应该关注这个语法限制背后的动机:从封装性角度考虑,把父类里不想让子类用到的属性和方法设计成私有的。