【python进阶——封装|继承|多态|类型注解】
面向对象编程:基于模板(类)去创建实体(对象),使用对象完成功能开发。
3大主要特性:封装,继承,多态
封装
私有不公开
私有成员(对象无法直接访问,需通过对象中的其他公开成员间接访问)
既然现实事物有不公开的属性和行为,那么作为现实事物在程序中映射的类,也应该支持
类中提供了私有成员的形式来支持。
私有成员变量:变量名以__开头(2个下划线)
私有变量也无法直接赋值取值
私有成员方法:方法名以__开头(2个下划线)
私有方法无法直接被类对象使用
class Student:
# 成员变量
name = None
__age = 15
def __say(self):
print(f"{self.name}的年龄是{self.__age}")
def wangba(self):
if self.__age>=18:
print("已满18岁可以网吧玩")
else:
self.__say()
print("未满18周岁,不可以进网吧")
stu1=Student()
stu1.name="小王"
#报错stu1.say()
#其它成员可以访问私有成员
stu1.wangba()#小王的年龄是15 未满18周岁,不可以进网吧
继承
本质上将已有的东西拿来改进新功能.
这样子是代码层面的继承,就是物理上继承
真正的继承,有自己的语法,就是class类声明时,如果这个类继承于别人,则新加一个括号内括类名
#单继承
class 类名(父类名)
#多继承
class 类名(父1,父2,..)
父类的代码子类也可用,子类只需新增父类没有的
如果只想继承,但是没有新增的,可以用pass补全语法(一般适用于单纯集成多个父类功能)
复写:子类的实例化对象可以调用父类的方法,并且子父同名的成员视为修改,以子类为准覆盖了父类
但是子类没有的去父类找成员,若多个父类有同名成员,优先级以继承顺序为主(从左到右),先继承保留,后继承被覆盖
形参若为一个类,则其子类也可传入,因为继承了父类的信息
class Phone2003:
size = None
producer = "huawei"
color = "green"
def call_by_3G(self):
print("3G通话")
class Phone2020:
size = None
producer = "huawei"
color = "red"
def call_by_4G(self):
print("4G通话")
class Phone2025(Phone2020):
color = ['black', 'white', 'yellow']
def call_by_5G(self):
print("5G通话")
# class Phone2026(Phone2025, Phone2020):报错,重复继承
class Phone2026(Phone2025, Phone2003):
def __init__(self):
#相当于通过成员函数(初始化方法__init__)声明了一个变量color
self.color=Phone2025.color
self.color.append(Phone2003.color) # 两个父类成员都可以继承并运算
def call_by_6G(self):
print("6G通话")
# 子类的实例化对象可以调用父类的方法,并且相同的视为修改,以子类为准,没有的去父类找
phone = Phone2025()
phone.call_by_4G() # 4G通话
phone.call_by_5G() # 5G通话
print(phone.color) # ['black', 'white', 'yellow']
phone2 = Phone2026()
phone2.call_by_6G() # 6G通话
phone2.call_by_5G() # 5G通话
phone2.call_by_4G() # 4G通话
phone2.call_by_3G() # 3G通话
print(phone2.color) # ['black', 'white', 'yellow', 'green']
调用复写前的数据
一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
如果又需要使用被复写的父类的成员,需要特殊的调用方式:
方式1:常规调用父类成员
使用成员变量:父类名.成员变量
使用成员方法:父类名.成员方法(self)
方式2: super()调用父类成员
使用成员变量:super().成员变量
使用成员方法:super().成员方法()
class Phone2020:
size = None
producer = "huawei"
color = "red"
def call_by_4G(self):
print("4G通话")
class Phone2025(Phone2020):
color = ['black', 'white', 'yellow']
def call_by_5G(self):
print("5G通话")
print(self.color)#因为被复写,所以是['black', 'white', 'yellow']
#两种方式调用复写前的父类成员
print(super().color)#red
print(Phone2020.color)#red
phone3=Phone2025()
phone3.call_by_5G()
多态
多态:同样的行为,传入不同的对象会得到不同的状态
常用于以父类为形参的函数,传入不同的子类,产生不同的状态,使之多态
class Animal:
def speak(se1f):
pass
class Dog(Animal):
def speak(self):
print(“汪汪汪”)
class cat(Animal):
def speak(self):
print(”喵喵喵”)
def make_noise(animal: Anima1):
animal.speak()
dog=Dog()
cat=Cat()
#虽然make_noise要求传入Animal类,但是由于狗猫类继承了Animal,有了父类的信息,也可传入
make_noise(dog)# 输出:汪汪汪
make_noise(cat)# 输出:喵喘喵
抽象类与抽象方法
为了完成多态,一般以父类为形参,传入不同的子类,产生不同的状态
这一过程中,父类都是pass,就是空实现,相当于说明有哪些方法
而具体的方法实现交给传入的子类
比如我父类规定了叫,那么子类可以多态实现狗叫猪叫等
由此产生抽象类与抽象方法
配合多态,父类抽象化来设计标准,而具体的子类来实现标准
此时外部声明函数通过形参父类而实参是其不同子类来实现多态
父类规定了标准
子类继承父类,然后实现标准
最后实现多态:声明一个函数,要求形参为父类,那么这个父类的所有子类都可传入,此时完成多态
类型注解
为了在pycharm中,后续对类对象的使用敲代码时可以自动提示,就需要在定义一个类时,告诉pycharm这是什么东西,参数是什么
由此有类型注解(本质类似于其他语言中的变量声明 int a = 5,但是类似,而非就这样)
法一:
变量名:类型说明
# 基础数据类型
var1: int = 10
var2: bool = True
var3: str = "uestc"
# 类对象
class Student:
pass
stu: Student = Student()
# 数据容器基本注解
a: list = [1, 2, "3"]
b: tuple = (1, 2, "3")
c: dict = {1: "3"}
# 数据容器详细注解
aa: list[int] = [1, 2, 3]
aaa: list[int, str, float] = [1, "2", 3.0]
bb: tuple[int] = (1, 2, 3)
cc: dict[int, str] = {1: "3"}
法二:
# 基础数据类型
var1 = 10 # type:int
# 类对象
class Student:
def func(self):
return Student()
stu = Student() # type:Student
# 数据容器基本注解
a = [1, 2, "3"] # type:list
# 数据容器详细注解
aa = [1, 2, 3] # type:list[int]
aaa = [1, "2", 3.0] # type:list[int, str, float]
bb = (1, 2, 3) # type:tuple[int]
cc = {1: "3"} # type:dict[int, str]
dd = stu.func() # type:Student #说明函数返回值是Studet类型
如果注解的是int型,但你给了str型,只会黄色警告但不会报错!即注解是提示性而非强制性的
函数注解
定义时
对函数形参注解
def fx(para1:int,para2:str): #说明参1为int,参2为str类型
对返回值注解
def fx(a,b)->int: #说明返回int类型
调用时对返回值进行注解
dd = stu.func() # type:Student #说明函数返回值是Studet类型
...
非规则混合类型注解UNION[type1,type2]
union相当于一个单变量占位符,限定了这个位置的变量必须是指定类型范围内
例如:要么int,要么float,除此以外不可
from typing import union
a:list[union[str,int]]=[1,2,"3"]
b:dict[str,union[int,str]]={"name":"小王","age":18}
非规则混合函数注解UNION[type1,type2]
def fx(data:union[int,float])->union[str,bool]:
...