初识对象 使用对象组织数据
在程序中是可以做到和生活中那样,设计表格、生产表格、填写表格的组织形式的
在程序中设计表格,我们称之为:设计类(class)
1 2 class Student : name = None
在程序中打印生产表格,我们称之为:创建对象
1 2 3 stu_1 = Student() stu_2 = Student()
在程序中填写表格,我们称之为:对象属性赋值
1 2 stu_1.name = "周杰轮" stu_2.name = "林军杰"
总结
生活中或是程序中,我们都可以使用设计表格、生产表格、填写表格的形式组织数据
进行对比,在程序中:
设计表格,称之为:设计类(class)
打印表格,称之为:创建对象
填写表格,称之为:对象属性赋值
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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)
运行结果
类的成员方法 类的定义和使用
类的使用语法:
创建类对象的语法:
成员变量和成员方法
1 2 3 4 5 class Student : name = None age = None def say_hi (self ): print (f"Hi大家好,我是{self.name} " )
1 2 3 stu = Student() stu.name = "周杰轮" stu.say_hi()
可以看出:类中:
不仅可以定义属性用来记录数据
也可以定义函数,用来记录行为
其中:
类中定义的属性(变量),我们称之为:成员变量
类中定义的行为(函数),我们称之为:成员方法
成员方法的定义语法
在类中定义成员方法和定义函数基本一致,但仍有细微区别:
1 2 def 方法名 (self, 形参1 , ......, 形参N ): 方法体
可以看到,在方法定义的参数列表中,有一个:self关键字
self关键字是成员方法定义的时候,必须填写的
它用来表示类对象自身的意思
当我们使用类对象调用方法的是,self会自动被python传入
在方法内部,想要访问类的成员变量,必须用self
注意事项
self关键字,尽管在参数列表中,但是传参的时候可以忽略它
如:
1 2 3 4 5 6 7 8 9 class Student : name = None def say_hi (self ): print ("Hello 大家好" ) def sey_hi2 (self, msg ): print (f"Hello 大家好" , {msg}") stu = Student() stu.say_hi1() # 调用的时候无需传参 stu.say_hi2(" 很高兴认识大家") # 调用的时候,需要传msg参数
可以看到,在传入参数的时候,self是透明的,可以不用理会它
总结
类是由哪两部分组成呢
类的属性,称之为:成员变量
类的行为,称之为:成员方法
注意:函数是写在类外的,定义在类内部,我们都称之为方法
类和成员方法的定义语法
1 2 3 4 5 class 类名称 : 成员变量 def 成员方法 (self,参数列表): 成员方法体 对象 = 类名称()
self的作用
表示类对象本身的意思
只有通过self,成员方法才能访问类的成员变量
self出现在形参列表中,但是不占用参数位置,无需理会
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 """ 演示面向对象类中的成员方法定义和使用 """ class Student : name = None def say_hi (self ): print (f"大家好,我是{self.name} ,欢迎大家多多关照" ) def say_hi2 (self, msg ): print (f"大家好,我是{self.name} ,{msg} " ) stu = Student() stu.name = "周杰轮" stu.say_hi2("哎呦不错呦" ) stu2 = Student() stu2.name = "林俊节" stu2.say_hi2("小伙子我看好你" )
运行结果
1 2 大家好,我是周杰轮,哎呦不错呦 大家好,我是林俊节,小伙子我看好你
类和对象 类和对象
基于类创建对象的语法:
类只是一种程序内的“设计图纸”,需要基于图纸生产实体(对象),才能正常工作
这种套路,称之为:面向对象编程
基于类创建对象
1 2 3 4 5 6 class Clock : id = None price = None def ring (self ): import winsound winsound.Beep(2000 , 3000 )
1 2 3 4 5 clock1 = Clock() clock1.id = "003032" clock1.price = 19.99 print (f"闹钟ID:{clock1.id } ,价格:{clock1.price} " )clock1.ring()
1 2 3 4 5 clock2 = Clock() clock2.id = "003033" clock2.price = 21.99 print (f"闹钟ID:{clock2.id } ,价格:{clock2.price} " )clock2.ring()
总结
现实世界的事物由什么组成
类也可以包含属性和行为,所以使用类描述现实世界事物是非常合适的
类和对象的关系是什么
类是程序中的“设计图纸”
对象是基于图纸生产的具体实体
什么是面向对象编程
面向对象编程就是使用对象进行编程
即,设计类,基于类创建对象,并使用对象来完成具体的工作
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 """ 演示类和对象的关系,即面向对象的编程套路(思想) """ 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()
运行结果
1 2 闹钟ID:003032,价格:19.99 闹钟ID:003033,价格:21.99
构造方法 属性(成员变量)的赋值
1 2 3 4 5 6 7 8 9 10 11 class Student: name = None # 名称 age = None # 年龄 tel = None # 手机号 student1 = Student() student1.name = "周杰轮" student1.age = 31 student1.tel = "18012340000" student2.name = "周杰轮" student2.age = 31 student2.tel = "18012340000"
上述代码中,为对象的属性赋值需要一次进行,略显繁琐。
有没有更加高效的方式,能够一行代码就完成
构造方法
Python类可以使用:__init__()方法,称之为构造方法
可以实现:
在创建类对象(构造类)的时候,会自动执行
在创建类对象(构造类)的时候,将传入参数自动传递给__init__()方法使用
1 2 3 4 5 6 7 8 9 10 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__,init前后都有2个下划线
构造方法也是成员方法,不要忘记在参数列表中提供:self
在构造方法内定义成员变量,需要使用self关键字
1 2 3 4 def __init__ (self, name, age, tel ): self.name = name self.age = age self.tel = tel
这是因为,变量是定义在构造方法内部,如果要成为成员变量,需要用self来表示
总结
构造方法的作用:
构建类对象的时候会自动运行
构建类对象的传参会传递给构造方法,借此特性可以给成员变量赋值
注意事项:
构造方法不要忘记self关键字
在方法内使用成员变量需要使用self
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 """ 演示类的构造方法 """ 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" ) print (stu.name)print (stu.age)print (stu.tel)
运行结果
1 2 3 4 Student类创建了一个类对象 周杰轮 31 18500006666
魔术方法 魔术方法
上文学习的__init__构造方法,是Python类内置的方法之一
这些内置的类方法,各自有各自特殊的功能,这些内置方法我们称之为:魔术方法
__init__:构造方法
__str__:字符串方法
__lt__:小于、大于符号比较
__le__:小于等于、大于等于符号比较
__eq__:==符号比较
__str__字符串方法
1 2 3 4 5 6 7 class Student : def __init__ (self, name, age ): self.name = name self.age = age student = Student("周杰轮" , 11 ) print (student) print (str (student))
当类对象需要被转换为字符串之时,会输出如上结果(内存地址)
内存地址没有多大作用,我们可以通过__str__方法,控制类转换为字符串的行为
1 2 3 4 5 6 7 8 9 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) print (str (student))
方法名:__str__
返回值:字符串
内容:自行定义
__lt__小于符号比较方法
1 2 3 4 5 6 7 class Student : def __init__ (self, name, age ): self.name = name self.age = age stu1 = Student("周杰轮" , 11 ) stu2 = Student("林军杰" , 13 ) print (stu1 < stu2)
直接对2个对象进行比较是不可以的,但是在类中实现__lt__方法,即可同时完成:小于符号和大于符号2种比较
1 2 3 4 5 6 7 8 9 10 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) print (stu1 > stu2)
方法名:__lt__
传入参数:other,另一个类对象
返回值:True或False
内容:自行定义
__le__小于等于比较符号方法
魔术方法:__le__可用于:<=、>=两种比较运算符上
1 2 3 4 5 6 7 8 9 10 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) print (stu1 >= stu2)
方法名:__le__
传入参数:other,另一个类对象
返回值:True或False
内容:自行定义
__eq__比较运算符实现方法
1 2 3 4 5 6 7 8 9 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__
传入参数:other,另一个类对象
返回值:True或False
内容:自行定义
不实现__eq__方法,对象之间可以比较,但是是比较内存地址,也即是:不同对象==比较一定是False结果。
实现了__eq__方法,就可以按照自己的想法来决定2个对象是否相等了
总结
方法
功能
__init__
构造方法,可用于创建类对象的时候设置初始化行为
__str__
用于实现类对象转字符串的行为
__lt__
用于2个类对象进行小于或大于比较
__le__
用于2个类对象进行小于等于或大于比较
__eq__
用于2个类对象进行相等比较
Demo
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 """ 演示Python内置的各类魔术方法 """ 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} " def __lt__ (self, other ): return self.age < other.age def __le__ (self, other ): return self.age <= other.age def __eq__ (self, other ): return self.age == other.age stu1 = Student("周杰轮" , 31 ) stu2 = Student("林军杰" , 31 ) print (stu1)print (stu2)print (stu1 <= stu2)print (stu1 >= stu2)print (stu1 == stu2)
运行结果
1 2 3 4 5 student类对象:name=周杰轮, age=31 student类对象:name=林军杰, age=31 True True True
封装 面向对象的三大特性
面向对象编程,是许多编程语言都支持的一种编程思想
简单理解是:基于模板(类)去创建实体(对象),使用对象完成功能开发
面向对象包含3大主要特性:封装、继承、多态
封装
封装表示的是,将现实世界事物的:属性、行为
封装到类中,描述为:成员变量、成员方法
从而完成程序对现实世界的描述
对用户隐藏的属性和行为
现实世界中的事物,有属性和行为,但是不代表这些属性和行为都是开放给用户使用的
私有成员
既然现实事物有不公开的属性和行为,那么作为现实事物在程序中映射的类,也应该支持
类中提供了私有成员的形式来支持
定义私有成员的方式非常简单,只需要:
私有成员变量:变量名以__开头(2个下划线)
私有成员方法:方法名以__开头(2个下划线)
即可完成私有成员的设置
使用私有成员
私有方法无法直接被类对象使用
1 2 3 4 5 6 7 8 9 10 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()
私有变量无法赋值,也无法获取值
1 2 3 4 5 6 7 8 9 10 11 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
私有成员无法被类对象使用,但是可以被其它的成员使用
1 2 3 4 5 6 7 8 9 10 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通话,并已设置为单核运行进行省电" )
总结
封装的概念是指将现实世界事物在类中描述为属性和方法,即为封装
什么是私有成员?为什么需要私有成员?
现实事物有部分属性和行为是不公开对使用者开放的。同样在类中描述属性和方法的时候也需要达到这个要求,就需要定义私有成员了
如何定义私有成员
成员变量和成员方法的命名均以__作为开头即可
私有成员的访问限制
类对象无法访问私有成员
类中的其它成员可以访问私有成员
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 """ 演示面向对象封装思想中私有成员的使用 """ 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通话,并已设置为单核运行进行省电" ) phone = Phone() phone.call_by_5g()
运行结果
1 2 让CPU以单核模式运行 电量不足,无法使用5g通话,并已设置为单核运行进行省电
封装的课后练习题讲解 Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 """ 讲解面向对象-封装特性课后练习题 设计带有私有成员的手机 """ class Phone : __is_5g_enable = True def __check_5g (self ): if self.__is_5g_enable: print ("5g开启" ) else : print ("5g关闭,使用4g网络" ) def call_by_5g (self ): self.__check_5g() print ("正在通话中" ) phone = Phone() phone.call_by_5g()
运行结果
继承的基础语法 继承的引出
1 2 3 4 5 class Phone : IMEI = None producer = None def call_by_4g (self ): print ("4g通话" )
1 2 3 4 5 6 7 8 class Phone2022 : IMEI = None producer = None face_id = True def call_by_4g (self ): print ("4g通话" ) def call_by_5g (self ): print ("2022最新5g通话" )
单继承
1 2 3 4 5 class Phone : IMEI = None producer = None def call_by_4g (self ): print ("4g通话" )
1 2 3 4 class Phone2022 (Phone ): face_id = True def call_by_5g (self ): print ("2022最新5g通话" )
继承分为:单继承和多继承
继承表示:将从父亲那里继承(复制)来成员变量和成员方法(不含私有)
多继承
Python的类之间也支持多继承,即一个类,可以继承多个父类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Phone : IMEI = None producer = None def call_by_5g (self ): print ("5g通话" ) class NFCReader : nfc_type = "第五代" producer = "HM" def read_card (self ): print ("读取NFC卡" ) def write_card (self ): print ("写入NFC卡" ) class RemoteControl : rc_type = "红外遥控" def control (self ): print ("红外遥控开启" ) class MyPhone (Phone, NFCReader, RemoteControl): pass
1 2 class 类名 (父类1 , 父类2 , ......, 父类N): 类内容体
多继承注意事项
多个父类中,如果有同名的成员,那么默认以继承顺序(从左到右)为优先级
即:先继承的保留,后继承的被覆盖
总结
继承就是一个类,继承另外一个类的成员变量和成员方法
语法:
1 2 class 类名 (父类1 , 父类2 , ......, 父类N): 类内容体
子类构建的类对象,可以
有自己的成员变量和成员方法
使用父类的成员变量和成员方法
单继承和多继承
单继承:一个类继承另一个类
多继承:一个类继承多个类,按照顺序从左向右依次继承
多继承中,如果父类有同名方法或属性,先继承的优先级高于后继承
pass关键字的作用是什么
pass是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思
Demo
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 30 31 32 33 34 35 36 37 """ 演示面向对象:继承的基础语法 """ class Phone : IMEI = None producer = "ITCAST" def call_by_4g (self ): print ("4g通话" ) class Phone2022 (Phone ): face_id = "10001" def call_by_5g (self ): print ("2022年新功能:5g通话" ) phone = Phone2022() print (phone.producer)phone.call_by_4g() phone.call_by_5g() class NFCReader : nfc_type = "第五代" producer = "HM" def read_card (self ): print ("NFC读卡" ) def write_card (self ): print ("NFC写卡" ) class RemoteControl : rc_type = "红外遥控" def control (self ): print ("红外遥控开启" ) class MyPhone (Phone, NFCReader, RemoteControl): pass phone = MyPhone() phone.call_by_4g() phone.read_card() phone.write_card() phone.control() print (phone.producer)
运行结果
1 2 3 4 5 6 7 HM 4g通话 2022 年新功能:5g通话4g通话 NFC读卡 NFC写卡 红外遥控开启
复写父类成员和调用父类成员 复写
子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写。
即:在子类中重新定义同名的属性或方法即可
1 2 3 4 5 6 7 8 9 class Phone : IMEI = None producer = "ITCAST" def call_by_5g (self ): print ("父类的5g通话" ) class MyPhone (Phone ): producer = "ITHEIMA" def call_by_5g (self ): print ("子类的5g通话" )
调用父类同名成员
一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
如果需要使用被复写的父类的成员,需要特殊的调用方式
方式1:调用父类成员
使用成员变量:父类名.成员变量
使用成员方法:父类名.成员方法(self)
方式2:使用super()调用父类成员
使用成员变量:super().成员变量
使用成员方法:super().成员方法()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Phone : IMEI = None producer = "ITCAST" def call_by_5g (self ): print ("父类的5g通话" ) class MyPhone (Phone ): producer = "ITCAST" def call_by_5g (self ): print (f"父类的品牌是:{Phone.producer} " ) Phone.call_by_5g(self) print (f"父类的品牌是:{super ().producer} " ) super ().call_by_5g() print ("子类的5g通话" )
总结
复写表示:对父类的成员属性或成员方法进行重新定义
复写的语法:在子类中重新实现同名成员方法或成员属性即可
在子类中,如何调用父类成员
方式1:调用父类成员
使用成员变量:父类名.成员变量
使用成员方法:父类名.成员方法(self)
方式2:使用super()调用父类成员
使用成员变量:super().成员变量
使用成员方法:super().成员方法()
注意:只可以在子类内部调用父类的同名成员,子类的实体类对象调用默认是调用子类复写的
Demo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Phone : IMEI = None producer = "ITCAST" def call_by_5g (self ): print ("使用5g网络进行通话" ) class MyPhone (Phone ): producer = "ITHEIMA" def call_by_5g (self ): print ("开启CPU单核模式,确保通话的时候省电" ) print (f"父类的品牌是:{super ().producer} " ) super ().call_by_5g() print ("关闭CPU单核模式,确保性能" ) phone = MyPhone() phone.call_by_5g() print (phone.producer)
运行结果
1 2 3 4 5 开启CPU单核模式,确保通话的时候省电 父类的品牌是:ITCAST 使用5g网络进行通话 关闭CPU单核模式,确保性能 ITHEIMA
变量的类型注解 为什么需要类型注解
因为PyCharm无法通过代码确定应传入什么类型,我们需要使用类型注解
类型注解
Python在3.5版本的时候引入了类型注解,以方便静态类型检查工具,IDE等第三方工具
类型注解:在代码中涉及数据交互的地方提供数据类型的注解(显示的说明)
主要功能:
帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示‘
帮助开发者自身对变量进行类型注释
支持:
变量的类型注解
函数(方法)形参列表和返回值的类型注解
类型注解的语法
为变量设置类型注解
基础语法:变量:类型
基础数据类型注解
1 2 3 4 var_1: int = 10 var_2: float = 3.1415926 var_3: bool = True var_4: str = "itheima"
类对象类型注解
1 2 3 class Student : pass stu: Student = Student()
基础容器类型注解
1 2 3 4 5 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"
容器类型详细注解
1 2 3 4 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 }
注意:
元组类型设置类型详细注解,需要将每一个元素都标记出来
字典类型设置类型详细注解,需要2个类型,第一个是key第二个是value
除了使用 变量:类型,这种语法做注解外,也可以在注释中进行类型注解
语法:
#type: 类型
在注释中进行类型注解
1 2 3 4 5 class Student : pass var_1 = random.randint(1 , 10 ) var_2 = json.loads(data) var_3 = func()
为变量设置注释,显示的变量定义,一般无需注解:
1 2 3 4 var_1: int = 10 var_2: list = [1 , 2 , 3 ] var_3: dict = {"itheima" : 666 } var_4: Student = Student()
如图,就算不写注解,也明确的知晓变量的类型
1 2 3 4 5 class Student : pass var_1: int = random.randint(1 , 10 ) var_2: dict = json.loads(data) var_3: Student = func()
一般,无法直接看出变量类型之时会添加变量的类型注解
类型注解的限制
类型注解主要功能在于:
帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示
帮助开发者自身对变量进行类型注释(备注)
并不会真正的对类型做验证和判断
也就是,类型注解仅仅是提示性的,不是决定性的
1 2 var_1: int = "itheima" var_2: str = 123
总结
什么是类型注解,有什么作用?
在代码中涉及数据交互之时,对数据类型进行显示的说明,可以帮助:
PyCharm等开发工具对代码做类型推断协助做代码提示
开发者自身做类型的备注
类型注解支持:
变量的类型注解
函数(方法)的形参和返回值的类型注解
变量的类型注解语法
语法1:变量: 类型
语法2:在注释中,# type: 类型
注意事项
类型注解只是提示性的,并非决定性的。数据类型和注解类型无法对应也不会导致错误
Demo
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 30 31 """ 演示变量的类型注解 """ import jsonimport randomvar_1: int = 10 var_2: float = 3.1415926 var_3: bool = True class Student : pass stu: Student = Student() my_list: list = [1 , 2 , 3 ] my_tuple: tuple = (1 , 2 , 3 ) my_dict: dict = {"itheima" : 666 } my_list: list [int ] = [1 , 2 , 3 ] my_tuple: tuple [int , str , bool ] = (1 , "itheima" , True ) my_dict: dict [str , int ] = {"itheima" : 666 } var_1 = random.randint(1 , 10 ) var_2 = json.loads('{"name": "zhangsan"}' ) def func (): return 10 var_3 = func() var_4: int = "itheima" var_5: str = 123
函数和方法类型注解 函数(方法)的类型注解-形参注解
在编写函数(方法),使用形参data的时候,工具没有任何提示
在调用函数(方法),传入参数的时候,工具无法提示参数类型
这些都是因为,我们在定义函数(方法)的时候,没有给形参进行注解
函数和方法的形参类型注解语法:
1 2 def 函数方法名 (形参名: 类型, 形参名: 类型, ...... ): pass
1 2 def add (x: int , y: int ): return x + y
1 2 def func (data: list ): pass
函数(方法)的类型注解-返回值注解
同时,函数(方法)的返回值也是可以添加类型注解的
语法如下:
1 2 def 函数方法名 (形参: 类型, ......, 形参: 类型 ) -> 返回值类型: pass
1 2 def add (x: int , y: int ) -> int : return x + y
1 2 def func (data: list [int ] ) -> list [int ]: pass
总结
函数(方法)可以为哪里添加注解?
函数(方法)的类型注解语法?
1 2 def 函数方法名 (形参: 类型, ......, 形参: 类型 ) -> 返回值类型: pass
注意,返回值类型注解的符号使用:->
Demo
1 2 3 4 5 6 7 8 9 10 """ 演示对函数(方法)进行类型注解 """ def add (x: int , y: int ): return x + y def func (data: list ) -> list : return data print (func(1 ))
运行结果
Union联合类型注解 Union类型
1 2 my_list: list [int ] = [1 , 2 , 3 ] my_dict: dict [str , int ] = {"age" : 11 , "num" : 3 }
1 2 my_list = [1 , 2 , "itcast" , "itheima" ] my_dict = {"name" : "周杰轮" , "age" : 31 }
1 2 3 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类型
Union联合类型注解,在变量注解、函数(方法)形参和返回注解中,均可使用
1 2 3 4 my_list: list [Union (int , str )] = [1 , 2 , "itcast" , "itheima" ] my_dict: dict [str , Union [str , int ]] = {"name" : "周杰轮" , "age" : 31 } def func (data: Union [int , str ] ) -> Union [int , str ]: pass
总结
什么是Union类型?
使用Union可以定义联合类型注解
Union的使用方式
导包:typing import Union
使用:Union[类型, ……, 类型]
Demo
1 2 3 4 5 6 7 8 9 """ 演示Union联合类型注解 """ from typing import Union my_list: list [Union [int , str ]] = [1 , 2 , "itheima" , "itcast" ] def func (data: Union [int , str ] ) -> Union [int , str ]: pass func()
多态 多态
多态,指的是:多种状态,即完成某个行为时,使用不同的对象会得到不同的状态
1 2 3 4 5 6 7 8 9 class Animal : def speak (self ): pass class Dog (Animal ): def speak (self ): print ("汪汪汪" ) class Cat (Animal ): def speak (self ): print ("喵喵喵" )
1 2 3 4 5 6 def make_noise (animal: Animal ): animal.speak() dog = Dog() cat = Cat() make_noise(dog) make_noise(cat)
同样的行为(函数),传入不同的对象,得到不同的状态
多态常作用在继承关系上
比如
函数(方法)形参声明接收父类对象
实际传入父类的子类对象进行工作
即:
以父类做定义声明
以子类做实际工作
用以获得同一行为,不同状态
抽象类(接口)
父类Animal的speak方法,是空实现
这种设计的含义是:
父类用来确定有哪些方法
具体的方法实现,由子类自行决定
这种写法,就叫做抽象类(也可以称之为接口)
抽象类:含有抽象方法的类称之为抽象类
抽象方法:方法体是空实现的(pass)称之为抽象方法
抽象类就好比定义一个标准,包含了一些抽象的方法,要求子类必须实现
1 2 3 4 5 6 7 8 9 10 class AC : def cool_wind (self ): """制冷""" pass def hot_wind (self ): """制热""" pass def swing_l_r (self ): """左右摆风""" pass
1 2 3 4 5 6 7 class Midea_AC (AC ): def cool_wind (self ): print ("美的空调核心制冷科技" ) def hot_wind (self ): print ("美的空调电热丝加热" ) def swing_l_r (self ): print ("美的空调无风感左右摆风" )
1 2 3 4 5 6 7 class GREE_AC (AC ): def cool_wind (self ): print ("格力空调变频省电制冷" ) def hot_wind (self ): print ("格力空调电热丝加热" ) def swing_l_r (self ): print ("格力空调静音左右摆风" )
配合多态,完成
抽象的父类设计(设计标准)
具体的子类实现(实现标准)
1 2 3 4 5 6 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)称之为抽象方法
抽象类的作用
多用于做顶层设计(设计标准),以便子类做具体实现
也是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法
并配合多态使用,获取不同的工作状态
Demo
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 """ 演示面向对象的多态特性以及抽象类(接口)的使用 """ 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 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)
运行结果
数据分析案例步骤1-文件读取 数据内容
1月份数据是普通文本,使用逗号分隔数据记录,从前到后分别是(日期,订单id,销售额,销售省份)
2月份数据是JSON数据,同样包含(日期,订单id,销售额,销售省份)
main.py
1 2 3 4 5 6 7 8 9 """ 面向对象:数据分析案例,主业务逻辑代码 实际步骤: 1. 设计一个类,可以完成数据的封装 2. 设计一个抽象类,定义文件读取的相关功能,并使用子类实现具体功能 3. 读取文件,生产数据对象 4. 进行数据需求的逻辑计算(计算每一天的销售额) 5. 通过PyEcharts进行图形绘制 """
data_define.py
1 2 3 4 5 6 7 8 9 10 11 """ 数据定义的类 """ class Record : def __init__ (self, date, order_id, money, province ): self.date = date self.order_id = order_id self.money = money self.province = province def __str__ (self ): return f"{self.date} , {self.order_id} , {self.money} , {self.province} "
file_define.py
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 """ 和文件相关的类定义 """ import jsonfrom data_define import Recordclass FileReader : def read_data (self ) -> list [Record]: """读取文件的数据,读到的每一条数据都转换为Record对象,将它们都封装到list内返回即可""" pass class TextFileReader (FileReader ): def __init__ (self, path ): self.path = path def read_data (self ) -> list [Record]: f = open (self.path, "r" , encoding="UTF-8" ) record_list: list [Record] = [] for line in f.readlines(): line = line.strip() data_list = line.split("," ) record = Record(data_list[0 ], data_list[1 ], int (data_list[2 ]), data_list[3 ]) record_list.append(record) f.close() return record_list class JsonFileReader (FileReader ): def __init__ (self, path ): self.path = path def read_data (self ) -> list [Record]: f = open (self.path, "r" , encoding="UTF-8" ) record_list: list [Record] = [] for line in f.readlines(): data_dict = json.loads(line) record = Record(data_dict["date" ], data_dict["order_id" ], int (data_dict["money" ]), data_dict["province" ]) record_list.append(record) f.close() return record_list if __name__ == '__main__' : text_file_reader = TextFileReader("D:/2011年1月销售数据.txt" ) json_file_reader = JsonFileReader("D:/2011年2月销售数据JSON.txt" ) list1 = text_file_reader.read_data() list2 = json_file_reader.read_data() for l in list1: print (l) for l in list2: print (l)
数据分析案例步骤2-数据计算 main.py
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 """ 面向对象:数据分析案例,主业务逻辑代码 实际步骤: 1. 设计一个类,可以完成数据的封装 2. 设计一个抽象类,定义文件读取的相关功能,并使用子类实现具体功能 3. 读取文件,生产数据对象 4. 进行数据需求的逻辑计算(计算每一天的销售额) 5. 通过PyEcharts进行图形绘制 """ from file_define import FileReader, TextFileReader, JsonFileReaderfrom data_define import Recordtext_file_reader = TextFileReader("D:/2011年1月销售数据.txt" ) json_file_reader = JsonFileReader("D:/2011年2月销售数据JSON.txt" ) jan_data: list [Record] = text_file_reader.read_data() feb_data: list [Record] = json_file_reader.read_data() all_data: list [Record] = jan_data + feb_data data_dict = {} for record in all_data: if record.date in data_dict.keys(): data_dict[record.date] += record.money else : data_dict[record.date] = record.money print (data_dict)
数据分析案例步骤3-可视化开发 main,py
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 30 31 32 33 34 35 36 """ 面向对象:数据分析案例,主业务逻辑代码 实际步骤: 1. 设计一个类,可以完成数据的封装 2. 设计一个抽象类,定义文件读取的相关功能,并使用子类实现具体功能 3. 读取文件,生产数据对象 4. 进行数据需求的逻辑计算(计算每一天的销售额) 5. 通过PyEcharts进行图形绘制 """ from file_define import FileReader, TextFileReader, JsonFileReaderfrom data_define import Recordfrom pyecharts.charts import Barfrom pyecharts.options import *from pyecharts.globals import ThemeTypetext_file_reader = TextFileReader("D:/2011年1月销售数据.txt" ) json_file_reader = JsonFileReader("D:/2011年2月销售数据JSON.txt" ) jan_data: list [Record] = text_file_reader.read_data() feb_data: list [Record] = json_file_reader.read_data() all_data: list [Record] = jan_data + feb_data data_dict = {} for record in all_data: if record.date in data_dict.keys(): data_dict[record.date] += record.money else : data_dict[record.date] = record.money bar = Bar(init_opts=InitOpts(theme=ThemeType.LIGHT)) bar.add_xaxis(list (data_dict.keys())) bar.add_yaxis("销售图" , list (data_dict.values()), label_opts=LabelOpts(is_show=False )) bar.set_global_opts( title_opts=TitleOpts(title="每日销售额" ) ) bar.render("每日销售额柱状图.html" )