Python继承与属性

学习地址

单继承

目标:

  • 单继承
  • 多继承
面向对象三大特性
  1. 封装:根据职责将属性和方法封装到一个抽象的类中
  2. 多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
  3. 继承:实现代码的重用,相同的代码不需要重复的编写
单继承
  1. 继承的概念:子类拥有父类所 有方法和属性
  2. 继承的语法:

    1
    2
    class class_name(father_name):
    pass
    • 子类继承自父类,拥有父类所有的方法和属性
    • 子类中应该根据职责,封装子类特有的属性和方法
    • 子类也称派生类,父类也称基类
  3. 继承的传递性
    简单来说,就是派生类的派生类可以调用基类的方法和属性。
    但是,注意这个传递的唯一性,只能单线继承,类似树状结构。

继承示例

1
2
3
4
5
6
7
8
9
10
11
12
13
class A:
def __init__(self,name):
self.name=name

class B(A):
def play(self):
print('%s is playing' %self.name)

b=B('abc')
b.play()

- - - - - - - - - - - -
abc is playing

方法的重写

当父类的方法不能满足子类的需求时,可以对方法进行重写(override)
重写父类方法有两种情况:

  1. 覆盖父类的方法:开发中如果父类的方法实现和子类的方法实现完全不同的情况,在子类中定义和父类同名的方法并实现
  2. 对父类的方法进行扩展:父类中封装的方法时子类要封装的方法的一部分,在子类中重写父类的方法,在需要的位置使用super().父类方法调用父类方法执行,方法中其他地方针对子类需求编写

关于super
Python中super是一个特殊的类,super()就是使用super类创建出来的对象,最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Animal:
def eating(self):
print('eating food')
def sleeping(self):
print("sleeping")

class Dog(Animal):
def bark(self):
print('wangwangwang')

class XiapTianQuan(Dog):
def fly(self):
print('flying')
'''
# 覆盖父类的方法,方法名与父类相同
def bark(self):
print('bark like a god')
'''

# 扩展父类的方法
def bark(self):
print('bark like a god,',end=" ")
super().bark()

xtq=XiapTianQuan()
xtq.bark()

- - - - - - - - - - - -
bark like a god, wangwangwang
使用父类名调用父类方法

早期的Python版本如果需要调用父类的方法还可以使用:父类名.方法(self),但不推荐,如果使用当前子类名会形成递归调用死循环

私有方法和属性

概念

对象所不希望公开的属性和方法,不希望外部访问,就是不对外公开,外界及子类都不能直接访问,通常用于做一些内部的事情

  1. 子类不能在自己的方法内部直接访问父类的私有属性或者方法
  2. 子类对象可以通过父类的公有方法间接访问到私有属性或者私有方法
定义方式

在定义属性或方法时,在属性名或者方法名前增加两个下划线__即可,定义的就是私有属性或方法。
这样,外界无法直接访问,但可以通过对象内部方法访问。

伪私有

在Python中,并没有真正意义的私有
在给属性、方法命名时,实际时对名称做了一些特殊处理,使得外界无法访问到
处理方式:在名称前面加上_类名,即_类名__名称
这种方法虽然也可以访问到,但在开发中不要使用这种方式,遵守应有的规则即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class A:
def __init__(self):
self.num1=10
self.__num2=20
def __test(self):
print('私有方法: num1 = %d num2 = %d' %(self.num1,self.__num2))
def test(self):
print('this is public function!')
self.__test()

class B(A):
def demo(self):
print("访问父类公开属性: num1 = %d " %self.num1)
self.test()
print('外挂访问私有属性(不推荐)')
print('私有属性: num2 = %d' %self._A__num2)

b=B()
b.demo()

- - - - - - - - - - - - -
访问父类公开属性: num1 = 10
this is public function!
私有方法: num1 = 10 num2 = 20
外挂访问私有属性(不推荐)
私有属性: num2 = 20

多继承

概念及语法

子类可以拥有多个父类、并且具有所有父类的属性和方法

1
2
class class_name(father_name1,father_name2,...):
pass

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class A:
def demo1(self):
print('you are in class A')

class B:
def demo2(self):
print('you are in class B')

class C(A,B):
def demo3(self):
self.demo1()
self.demo2()

c=C()
c.demo3()

- - - - - - - - - - - -
you are in class A
you are in class B

同名方法与属性

如果继承的不同父类中存在同名的方法或者属性,子类对象在调用时会按照继承列表的先后顺序执行一次。
开发时,应尽量避免这种容易产生混淆的情况,或者放弃使用多继承

解决多继承重名问题的MRO(方法搜索顺序)
  • Python中针对类提供了一个内置属性__mro__可以查看方法搜索顺序
  • MRO即method_resolution_order,主要用于在多继承时判断方法、属性的调用路径
1
2
3
4
print(C.__mro__)

- - - - - -
(<class '__main__.C'>, <class '__main__.A'>, <class '__main__.B'>, <class 'object'>)
新式类和旧式类

object时Python为所有对象提供的基类,提供有一些内置的属性和方法,可以使用dir函数查看,Python3默认新式类,如果没有指定父类默认object

  • 新式类:以object为基类的类,推荐使用
  • 旧式类:不以object为基类的类,不推荐使用

这个会影响方法搜索顺序,建议新式类。