面向对象的三大特性:
- 封装:根据职责将属性或方法 封装 到一个抽象的类中
- 继承:实现代码的重用,相同的代码不需要重复的编写
- 多态:不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活度
1. 单继承
1.1 继承的概念、语法和特点
- 继承的概念:子类拥有父类的所有方法和属性
- 继承的语法
class 类名(父类名)
pass
- 子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
- 子类中应该根据职责,封装子类特有的属性和方法
- 专业术语
Dog
类是Animal
类的 子类,Animal
类是Dog
类的父类,Dog
类从Animal
类 继承Dog
类是Animal
类的 派生类,Animal
类是Dog
类的基类,Dog
类从Animal
类 派生
- 继承的传递性
C
类从B
类继承,B
类又从A
类继承,那么C
类就具有B
类和A
类的所有属性和方法- 子类 拥有 父类 以及 父类的父类 中封装的所有属性和方法
class Animal:
def eat(self):
print("Eat")
def drink(self):
print("Drink")
def sleep(self):
print("Sleep")
class Dog(Animal):
def bark(self):
print("Wangwangwang")
class Husky(Dog):
def smile(self):
print("Hahahahaha")
# 创建一个对象 - Dog
lovelydog = Dog()
lovelydog.eat()
lovelydog.drink()
lovelydog.sleep()
lovelydog.bark()
lovelydog.smile()
output:
Eat
Drink
Sleep
Wangwangwang
Hahahahaha
1.2 方法的重写
-
子类拥有父类的所有方法和属性
-
子类继承自父类,可以直接享受父类中已经封装好的方法,不需要再次开发
-
当父类的方法实现不能满足子类需求时,可以对方法进行重写(override)
重写父类方法有两种情况:
- 覆盖父类的方法
- 对父类方法进行扩展
1.1.1 覆盖父类的方法
-
如果在开发中,父类的方法实现和子类的方法实现完全不同,就可以使用覆盖的方式,在子类中重新编写父类的方法实现
-
实现方式:在子类中定义一个和父类同名的方法。
-
重写之后,在运行时,只会调用子类中重写的方法,而不会再调用父类封装的方法。
# 在上面代码中修改以下内容
class Husky(Dog):
def smile(self):
print("Hahahahaha")
# 在子类中重写bark方法
def bark(self):
print("I can speak human language!")
# 创建一个对象 - Dog
lovelydog = Husky()
# 如果子类中重写了父类的方法,在使用子类对象调用的方法时,会调用子类中重写的方法
lovelydog.bark()
output:
I can speak human language!
1.1.2 扩展父类的方法
- 如果在开发中,子类的方法实现中包含父类的方法实现,即父类原本封装的方法实现是子类方法的一部分,就可以使用扩展的方式。
- 实现方式:
– 1. 在子类中重写父类的方法
– 2. 在需要的位置使用super().父类方法
来调用父类方法的执行
– 3. 代码其他位置针对子类的需求,编写子类特有的代码实现
- 关于super
– 在python中,super
是一个特殊的类
–super()
就是使用super
类创建出来的对象
– 最常使用的场景就是在重写父类方法时,调用在父类中封装的方法实现
# 接上代码
class Husky(Dog):
def smile(self):
print("Hahahahaha")
def bark(self):
# 1. 针对子类特有的需求,编写代码
print("I can speak human language!")
# 2. 使用super().调用原本在父类中封装的方法
super().bark()
# 3. 增加其他子类代码
print("I am the most handsome dog!")
# 创建一个对象 - Dog
lovelydog = Husky()
lovelydog.bark()
output:
I can speak human language!
Wangwangwang
I am the most handsome dog!
1.3 父类的私有属性和私有方法
- 子类对象不能在自己的方法内部,直接访问父类的私有属性或私有方法
- 子类对象可以通过父类的公有方法间接访问到私有属性或私有方法
– 私有属性、方法是对象的隐私,不对外公开,外界以及子类都不能直接访问
– 私有属性、方法通常用于做一些内部的事情
举个栗子
- B的对象不能直接访问
__num2
属性 - B的对象不能在
demo
方法内访问__num2
属性
class A:
def __init__(self):
self.num1 = 100
self.__num2 = 200
def __test(self):
print("私有方法 %d %d"% (self.num1, self.__num2))
class B(A):
def demo(self):
# 1. 在子类的对象方法中,不能访问父类的私有属性
# print("访问父类的私有属性 %d" % self.__num2) ——会出现报错
# 2. 在子类的对象方法中,不能调用父类的私有方法
# self.__test() ——会出现报错
pass
# 创建一个子类对象
b = B()
print(b)
# 在外界不能直接访问对象的私有属性/调用私有方法
- B的对象可以在
demo
方法内,调用父类的test
方法 - 父类的
test
方法内部,能够访问__num2
属性和__test
方法
class A:
def __init__(self):
self.num1 = 100
self.__num2 = 200
def __test(self):
print("私有方法 %d %d"% (self.num1, self.__num2))
def test(self):
print("父类的公有方法 %d" % self.__num2)
self.__test()
class B(A):
def demo(self):
# 访问父类的公有属性
print("子类方法 %d" % self.num1)
# 调用父类的公有方法
self.test()
# 创建一个子类对象
b = B()
b.demo()
output:
子类方法 100
父类的公有方法 200
私有方法 100 200