面向对象
初识对象
使用对象组织数据
1.在程序中设计表格,我们称之为:设计类(class)
class Student :
name = None #记录学生名字
2.在程序中打印生产表格,我们称之为:创建对象
#基于类创建对象
stu_1 = Student()
stu_2 = Student()
3.在程序中填写表格,我们称之为:对象属性赋值
stu_1.name = "周杰伦" #为对象1赋予名称属性值
stu_2.name = "林俊杰" #为对象2赋予名称属性值
例如(个人登记表):
#设计一个类
class Student :
name = None #记录学生姓名
gender = None #性别
nationality = None #国籍
native_place = None #籍贯
age = None #年龄
#创建一个对象
stu_1 = Student()
#对象属性进行赋值
stu_1.name = "林俊杰"
stu_1.gender = "男"
stu_1.nationality = "中国"
stu_1.native_place = "山东省"
stu_1.age = 31
#获取对象中记录的信息
print(stu_1.name)
print(stu_1.gender)
print(stu_1.nationality)
print(stu_1.native_place)
print(stu_1.age)
#输出
林俊杰
男
中国
山东省
31
成员方法
类的定义和使用
class 类名称 :
#类的属性
#类的行为
- class是关键字,表示要定义类了
- 类的属性,即定义在类中的变量(成员变量)
- 类的行为,即定义在类中的函数(成员方法)
创建类对象的语法 :
对象 = 类名称()
成员变量和成员方法
class Student :
name = None #学生的姓名
age = None #学生的年龄
def say_hi(self) :
print(f"Hi大家好,我是{self.name}")
stu = Student()
stu.name = "周杰伦"
stu.say_hi() #输出:Hi大家好,我是周杰伦
可以看到,类中 :
- 不仅可以定义属性来记录数据
- 也可以定义函数,用来记录行为
其中 :
- 类中定义的属性(变量),我们称之为 :成员变量
- 类中定义的行为(函数),我们称之为: 成员方法
成员方法的定义语法
在类中定义成员方法和定义函数基本一致,但仍有细微区别 :
def 方法名(self,形参1,形参2,......,形参N) :
方法体
可以看到,在方法定义的参数列表中,有一个:self关键字
self关键字是成员方法定义的时候,必须填写的
- 它用来表示类对象的意思
- 当我们使用类对象调用方法的时候,self会自动被python传入
- 在方法内部想要访问类的成员变量,必须使用self
self关键字,尽管在参数列表中,但是传参的时候可以忽略它。
如 :
class Student() :
name = None
def say_hi(self) : #想要访问成员属性必须用self
print(f"Hello,大家好,我是{self.name}")
def say_hi2(self,msg) :
print(f"Hello,大家好,我是{self.name},{msg}")
stu = Student()
stu.say_hi() #调用的时候无需传参
stu.say_hi2("很高兴认识大家")#调用的时候,需要msg传参
可以看到,在传入参数的时候,self是透明的,可以不用理会它。
类和对象
类只是一种程序内的”设计图纸“,需要基于图纸生产实体(对象),才能正常工作,这种套路被称之为:面向对象编程
核心 :设计类,基于类创建对象,由对象做具体工作
例如(设计一个闹钟) :
class Clock :
id = None #序列号
price = None #价格
def ring(self) :
import winsound
winsound.Beep(2000,3000) #(频率,响铃时间)
#构建两个闹钟对象并让其工作
clock1 = Clock()
clock1.id = "003032"
clock1.price = 19.99
print(f"闹钟ID:{clock1.id},价格:{clock1.price}")
clock1.ring
clock2 = Clock()
clock2.id = "003033"
clock2.price = 21.99
print(f"闹钟ID:{clock2.id},价格:{clock2.price}")
clock2.ring
构造方法
python类可以使用:
__init__() 称之为构造方法
可以实现:
- 在创建类对象(构造类)的时候,会自动执行。
- 在创建类对象(构造类)的时候,将传入参数自动传递给__init__()方法使用
例如:
class Student() :
name = None
age = None
tel = None #成员变量可省略
def __init__(self,name,age,tel) :
self.name = name
self.age = age
self.tel = tel
print("Student类创建了一个对象")
stu = Student("周杰伦",31,"18500006666")
构造方法注意事项:
-
init前后都有两个下划线_
-
构造方法也是成员方法,不要忘记在参数列表中提供:self
-
在构造方法内定义成员变量,需要使用self关键字
class Student() : def __init__(self,name,age,tel) : self.name = name self.age = age self.tel = tel
其他内置方法
上文学习的__init__构造方法,是python类内置的方法之一
这些内置的类方法,各自有各自的特殊功能,这些内置方法我们称之为:魔术方法
魔术方法:__int__构造方法,__str__字符串方法,__lt__小于,大于符号比较,__le__小于等于,大于等于符号比较,eq==符号比较,…
__str__字符串方法
class Student :
def __init__(self,name,age) :
self.name = name
self.age = age
student = Student("周杰伦",11)
print(student) #输出:<__main__.Student object at 0x0000016597529850>
print(str(student)) #输出:<__main__.Student object at 0x0000016597529850>
当类对象需要被转换为字符串时,会输出如上结果(内存地址)
内存地址没有多大作用,我们可以通过__str__方法,控制类转换为字符串的行为。
class Student :
def __init__(self,name,age) :
self.name = name
self.age = age
def __str__(self) :
return(f"Student类对象,name = {self.name},age = {self.age}")
student = Student("周杰伦",11)
print(student) #Student类对象,name = 周杰伦,age = 11
print(str(student)) #Student类对象,name = 周杰伦,age = 11
__lt__小于符号比较方法
class Student :
def __init__(self,name,age) :
self.name = name
self.age = age
stu1 = Student("周杰伦",11)
stu2 = Student("林俊杰",13)
print(stu1<stu2) #报错
直接对两个对象进行比较是不可以的,但是在类中实现__lt__方法,即可同时完成:小于符号 和大于符号 2种比较
class Student :
def __init__(self,name,age) :
self.name = name
self.age = age
def __lt__(self,other) :
return self.age < other.age
stu1 = Student("周杰伦",11)
stu2 = Student("林俊杰",13)
print(stu1 < stu2) #结果为:True
print(stu1 > stu2) #结果为:False
- 方法名:lt
- 传入参数:other,另一类对象
- 返回值:True或False
- 内容:自行定义
__le__小于等于比较符号方法
方法逻辑上与__lt__一样
class Student :
def __init__(self,name,age) :
self.name = name
self.age = age
def __le__(self,other) :
return self.age < other.age
stu1 = Student("周杰伦",11)
stu2 = Student("林俊杰",13)
print(stu1 <= stu2) #结果为:True
print(stu1 >= stu2) #结果为:False
eq,比较运算符实现方法
class Student :
def __init__(self,name,age) :
self.name = name
self.age = age
def __eq__(self,other) :
return self.age < other.age
stu1 = Student("周杰伦",11)
stu2 = Student("林俊杰",11)
print(stu1 == stu2) #结果为:True
- 不实现__eq__方法,对象之间可以比较,但是是比较内存地址,也即是:不同对象 == 比较一定是Flase结果
- 实现了__eq__方法,就可以按照自己的想法来决定两个对象是否相等了
封装
面向对象的三大特征
面向对象编程,是许多编程语言都支持的一种编程思想
简单理解是:基于模板(类)去创建实体(对象),使用对象完成功能开发
面向对象包含三大主要特征:
- 封装
- 继承
- 多态
封装
封装表示的是,将现实世界事物的:
- 属性
- 行为
封装到类中,描述为:
- 成员变量
- 成员方法
从而完成程序对现实世界事物的描述
私有成员
既然现实事物有不公开的属性和行为,那么作为显示事物在成语中映射的类,也应该支持
类中提供了私有成员的形式来支持
- 私有成员变量
- 私有成员方法
定义私有成员的方式非常简单,只需要:
- 私有成员变量:变量名以__开头(两个下划线)
- 私有成员方法:方法名以__开头
即可完成私有成员的设置
class Phone :
IMEI = None #序列号
producer = None #厂商
__current_voltage =None #当前电压 私有成员变量
def call_by_5G(self) :
print("5G通话已开启")
def __keep_single_core(self) :
print("让cpu以单核模式运行以节省电量") #私有成员方法
使用私有成员
私有方法无法直接被类对象使用
class Phone :
IMEI = None #序列号
producer = None #厂商
__current_voltage =None #当前电压 私有成员变量
def call_by_5G(self) :
print("5G通话已开启")
def __keep_single_core(self) :
print("让cpu以单核模式运行以节省电量") #私有成员方法
phone = Phone()
phone.__keep_single_core() #使用私有方法 报错
私有变量无法赋值,也无法获取值
class Phone :
IMEI = None #序列号
producer = None #厂商
__current_voltage =None #当前电压 私有成员变量
def call_by_5G(self) :
print("5G通话已开启")
def __keep_single_core(self) :
print("让cpu以单核模式运行以节省电量") #私有成员方法
phone = Phone()
phone.__current_voltage = 33 #不报错,但无效
print(phone.__current_voltage) #报错无法使用
私有成员无法被类对象使用,但是可以被其他的成员使用
class Phone :
__current_voltage = 0.5 #当前手机运行电压
def __keep_single_core(self) :
print("让cpu以单核模式运行")
def call_by_5G(self) :
if self.__current_voltage >=1 :
print("5G通话已开启")
else :
self.__keep_single_core()
print("电量不足,无法使用5G通话,并已设置为单核运行进行省电")
继承
继承基础语法
单继承
class Phone :
IMEI = None #序列号
producer = None #厂商
def call_by_4g(self) :
print("4g通话")
class Phone2024(Phone) :
face_id = True
def call_by_5g() :
print("2024最新5g通话")
class 类名(父类名) ;
类内容体
继承分为:单继承和多继承
继承表示:将从父类那里继承(复制)来成员变量和成员方法(不含私有)
多继承
python的类之间也支持多继承,即一个类,可以继承多个父类
class Phone :
IMEI = None #序列号
producer = "HH" #厂商
def call_by_4g(self) :
print("4g通话")
class NFCReader : #NFC读卡器
nfc_type = "第五代"
producer = "HH"
def read_card(self) :
print("NFC读卡")
def write_card(self) :
print("NFC写卡")
class RemoteControl : #远程控制
re_type = "红外遥控"
def control(self) :
print("红外遥控开启了")
class MyPhone(Phone,NFCReader,RemoteControl) :
pass #用来补全语法
phone = MyPhone()
多继承注意事项
多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级。
即:先继承的保留,后继承的覆盖(谁先来谁的优先级高)
复写和使用父类成员
复写
子类继承父类的成员属性和成员方法后,如果对其“不满意“,那么可以进行复写
即:在子类中重新定义同名属性或方法即可
class Phone() :
IMEI = None
producer = "ITCAST"
def call_by_5G(self) :
print("父类的5G通话")
class MyPhone(Phone) :
producer = "IT" #复写父类属性
def call_by_5G : #复写父类方法
print("子类的5G通话")
调用父类成员
一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
如果需要使用被复写的父类成员,需要特殊的调用方法:
- 方式1
使用成员变量:父类名.成员变量
使用成员方法:父类名.成员方法(self)
- 方式2
使用super()调用父类成员
使用成员变量:super().成员变量
使用成员方法:super().成员方法()
class Phone() :
IMEI = None
producer = "ITCAST"
def call_by_5G(self) :
print("父类的5G通话")
class MyPhone(Phone) :
producer = "IT" #复写父类属性
def call_by_5G :
#方式1
print(f"父类的品牌是:{Phone.producer}")
Phone.call_by_5G(self)
#方式2
print(f"父类的品牌是:{super().producer}")
super().call_by_5G()
print("子类的5G通话")
类型注解
变量的类型注解
python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具。
类型注解:在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)。
主要功能:
- 帮助第三方IDE工具(如pycharm)对代码进行类型推断,协助做代码提示
- 帮助开发者自身对变量进行类型注释
支持:
- 变量的类型注释
- 函数(方法)形参列表和返回值的类型注释
类型注解的语法
基础语法 : 变量:类型
基础数据类型注解
var_1 : int = 10
var_2 : float = 3.1415926
var_3 : bool = True
var_4 : str = "itheima"
类对象类型注解
class Student :
pass
stu : Student = Student()
基础容器类型注解
my_list : list = [1,2,3]
my_tuple : tuple = (1,2,3)
my_set : set = {1,2,3}
my_dict : dict = {"itheima" : 666}
my_str : str = "itheima"
容器类型详细注解
my_list : list[int] = [1,2,3]
my_tuple : tuple[str,int,bool] = ["itheima",666,True]
my_set : set[int] = {1,2,3}
my_dict : dict[str,int] = {"itheima" : 666}
注意
- 元组类型设置类型详细注解,需要将每一个元素都标记出来
- 字典类型设置类型注解,需要两个类型,第一个是key第二个是value
除了使用 变量:类型 ,这种语法做注解外,也可以在注释中进行类型注解
语法:
#type : 类型
在注释中进行类型注解
class Student :
pass
var_1 = random.randint(1,10) #type : int
var_2 = json.loads(data) #type : dict[str,int]
var_3 = func() #type : Student
为变量设置注解,显示的变量定义,一般无需注解:
var_1 : int = 10
var_2 : float = 3.1415926
var_3 : bool = True
var_4 : str = "itheima"
如图,就算不写注解,也明确的知晓变量的类型
一般,无法直接看出变量类型之时会添加变量的类型注解
类型注解主要功能在于:
- 帮助第三方IDE工具(如pycharm)对代码进行数据类型推断,协助做代码提示
- 帮助开发者自身对变量进行类型注解(备注)
并不会真正的对类型做验证和判断。
也就是,类型注解仅仅是提示性的,不是决定性的
var_1 : int = "itheima"
bar_2 : str = 123
#不会报错
函数(方法)的类型注解
函数和方法的形参类型注解语法:
def 函数方法名(形参:类型) :
pass
对返回值进行注解:
def 函数方法名(形参:类型......) -> 返回值类型
pass
def func(data:list)-> list:
return data
print(func(1)) #输出1 提示性而非决定性
Union类型
from typing import union
my_list:list[union[str,int]] = [1,2,"itheima","itcast"]
my_dict:dict[str,union[str,int]] = {"name":"周杰伦","age":31}
使用Union[类型,…,类型]
可以定义联合类型注解
union联合类型注解,在变量注解,函数(方法)形参和返回值注解中,均可使用
my_list:list[Union(int,str)] = [1,2,"itheima","itcast"]
my_dict:dict[str,Union[str,int]] = {"name":"周杰伦","age":31}
def func(data:Union[int,str]) ->Union[int,str] :
pass
多态
多态介绍
多态,指的是:多种状态,即完成某个行为时,使用不同的对象会得到不同的状态
理解:
class Animal :
def speak(self) :
pass
class Dog(Animal) :
def speak(self) :
print("汪汪汪")
class Cat(Animal) :
def speak(self) :
print("喵喵喵")
def make_noise(animal:Animal) :
animal.speak()
dog = Dog()
cat = Cat()
make_noise(dog) #输出:汪汪汪
make_noise(cat) #输出:喵喵喵
同样的行为(函数),传入不同的对象,得到不同的状态
多态常作用在继承关系上
比如
- 函数(方法)形参声明接收父类对象
- 实际传入父类的子类对象进行工作
即:
- 以父类做定义声明
- 以子类做实际工作
- 用以获得同一行为,不同状态
抽象类(接口)
class Animal :
def speak(self) :
pass
class Dog(Animal) :
def speak(self) :
print("汪汪汪")
class Cat(Animal) :
def speak(self) :
print("喵喵喵")
def make_noise(animal:Animal) :
animal.speak()
dog = Dog()
cat = Cat()
make_noise(dog) #输出:汪汪汪
make_noise(cat) #输出:喵喵喵
上述代码中 父类的Animal的speak方法,是空实现
这种设计的含义是:
- 父类用来确定有哪些方法
- 具体的方法实现,由子类自行决定
这种写法,就叫做抽象类(也可以称之为接口)
抽象类:含有抽象方法的类称之为抽象类
抽象方法:方法体是空实现(pass)称之为抽象方法
抽象类就好比定义一个标准,包含了一些抽象的方法,要求子类必须实现。
class AC :
def cool_wind(self) :
'''制冷'''
pass
def hot_wind(self) :
'''制热'''
pass
def swing_l_r(self) :
'''左右摆风'''
pass
class Midea_AC(AC) :
def cool_wind(self) :
print("美的空调核心制冷科技")
def hot_wind(self) :
print("美的空调电热丝加热")
def swing_l_r(self) :
print("美的空调无风感左右摆风")
class GREE_AC(AC) :
def cool_wind(self) :
print("格力空调变频省电制冷")
def hot_wind(self) :
print("格力空调电热丝加热")
def swing_l_r(self) :
print("格力空调静音左右摆风")
def make_cool(ac:AC) :
ac.cool_wind()
midea_ac = Midea_AC()
gree_ac = GREE_AC()
make_cool(midea_ac) #输出:美的空调核心制冷科技
make_cool(gree_ac) #输出:格力空调变频省电制冷
体是空实现(pass)称之为抽象方法
抽象类就好比定义一个标准,包含了一些抽象的方法,要求子类必须实现。
class AC :
def cool_wind(self) :
'''制冷'''
pass
def hot_wind(self) :
'''制热'''
pass
def swing_l_r(self) :
'''左右摆风'''
pass
class Midea_AC(AC) :
def cool_wind(self) :
print("美的空调核心制冷科技")
def hot_wind(self) :
print("美的空调电热丝加热")
def swing_l_r(self) :
print("美的空调无风感左右摆风")
class GREE_AC(AC) :
def cool_wind(self) :
print("格力空调变频省电制冷")
def hot_wind(self) :
print("格力空调电热丝加热")
def swing_l_r(self) :
print("格力空调静音左右摆风")
def make_cool(ac:AC) :
ac.cool_wind()
midea_ac = Midea_AC()
gree_ac = GREE_AC()
make_cool(midea_ac) #输出:美的空调核心制冷科技
make_cool(gree_ac) #输出:格力空调变频省电制冷