python
1.字面量
(1)整数
类似数学上面的整数,包括整数和负数
1 | print(10) # 输出 10 |
(2)浮点数
类似数学上面的小数
1 | print(13.14) # 输出 13.14 |
(3)字符串
定义: 字符串(string),又称文本,是由任意数量的字符如中文、英文、各类符号、数字等组成。所以叫做字符的串。
需要用 双引号” “ 或者 单引号’ ’ 或者 三引号”“” “”” 包围起来。
1 | print("字符串") # 输出 字符串 |
2.注释
定义:在程序代码中对程序进行解释的文字
作用:注释不是程序,不能被执行,只是对代码进行解释说明作用,可以让代码的可对性提高
- 单行注释:以#开头,右边的所有文字为注释文字#号和注释内容一般建议以一个空格隔开.、
- 多行注释: 以 一对三个双引号 引起来 (“”” “””)来解释说明一段代码的作用使用方法
1 | # 我是单行注释 |
3.变量
在程序运行的时候,能存储计算结果或者能表示值的抽象概念
(1)变量的定义格式
1 | """ |
(2)变量的赋值
1 | """ |
4数据类型的查看
变量是没有类型的,但是数据是有类型的
- 可以使用type(变量名)查看数据的类型
1 | # 1.使用print直接输出类型信息 |
5.数据类型转换
在一定的条件下,数据的类型可以转换
5.1转为整数
1 | # 字符串转为整数 |
5.2转为浮点数
使用 float(x) ,将x转换为一个浮点数
1 | #字符串转浮点数 |
5.3转为字符串
1 | #使用 str(x) ,将x转换为一个字符串 |
6.标识符
用户在编程的时候所使用的一系列用于给变量、类、方法等命名的名字
略
7.运算符
略
8.字符串的使用
三种定义方式
1 | 单引号定义法:name = '断桥圆月' |
- 字符串拼接
1 | print("断桥圆月" + "study") # 输出 观止study |
- 字符串拼接的格式化
1 | name = "study" |
1 | hobby = "study" |
格式符号 | 意义 |
---|---|
%S | 将内容转换成字符串,放入占位位置 |
%d | 将内容转换成整数,放入占位位置 |
%f | 将内容转换成浮点型,放入占位位置 |
1 | name = "study" |
- 格式化的精度控制
1 | age = 18 # %5d 表示将整数的宽度控制在5位,用三个空格补足宽度 |
- 字符串格式化的另外方式
1 | age = 18 |
缺点:
- 无法做精度控制
- 不理会数据类型
9.数据输入
使用imput()语句进行输入
1 | name = input() # 输入 断桥圆月 用name变量来接收输入的数值 |
- 可在input()中输入提示信息,将打印在控制台
1 | name = input(”tell me your name?“) |
- 输入的数值都将转为字符串类型,可通过数据类型转换获取需要的数据类型
1 | name = input() # 输入 5 |
10判断
10.1逻辑运算符
and逻辑与运算,等价于数学中的“且” a and b 当 a 和 b 两个表达式都为真时,a and b 的结果才为真,否则为假。
or逻辑或运算,等价于数学中的“或” a or b 当 a 和 b 两个表达式都为假时,a or b 的结果才是假,否则为真。
not逻辑非运算,等价于数学中的“非” not a 如果 a 为真,那么 not a 的结果为假;如果 a 为假,那么 not a 的结果为真。相当于对 a 取反。
- 在python当中,以下变量都会被当成False:任何数值类型的0、””或’’空字符串、空元组()、空列表[]、空字典{}等。
- and和or运算符会将其中一个表达式的值作为最终结果,而不是将 True 或者 False 作为最终结果
- 当遇到一个语句当中有多个逻辑运算符时,按照优先级not>and>or顺序来运算
运算
and运算符
当两边都是表达式时:and两边的表达式都为真时才为真,否则为假
1 | print(15 > 10 and 15 > 6) # 打印 True |
不全是表达式
- 左边表达式的值为假,左边表达式的值作为最终结果。
- 左边表达式的值为真,右边表达式的值作为最终结果。
1 | print({} and 15) # 打印 {} |
or运算符
- 两边都是表达式:or两边的表达式只要有一个真即为真,否则为假
1 | print(15 > 10 or 15 > 6) # 打印 True |
不全是表达式
左边表达式的值为假,右边表达式的值作为最终结果。
左边表达式的值为真,左边表达式的值作为最终结果。
1 | print({} or 15) # 打印 15 |
not运算符
- 当表达式为真时,运算结果就为假;当表达式为假时,运算结果为真。not可以理解为
取反
的意思
10.2 if
条件为True 执行,条件为False跳过
略
11循环
while循环
1 | while 条件: |
1 | i = 0 |
for循环
1 | for 临时变量 in 待处理数据集(可迭代对象): |
1 | # 定义字符串name |
range语句
- 语法一: range(num)
1 | # 获取一个从0开始,到num结束的数字序列(不含num本身) |
- 语法二: range(num1,num2)
1 | # 获得一个从num1开始,到num2结束的数字序列(不含num2本身) |
- 语法三: range(num1, num2, step)
1 | # 获得一个从num1开始,到num2结束的数字序列(不含num2本身) |
continue关键字
临时跳过: 暂时跳过本次循环,直接进行下一次
break关键字
直接结束: 提前退出循环,不再继续
12函数
1 | # 定义 |
1 | # 定义 |
1 | # 定义 |
1 | # 定义 |
1.变量的作用域
(1) 局部变量
定义在函数体内部的变量,即只在函数体内部生效
1 | def test(): |
全局变量
在函数体内、外都能生效的变量
1 | num = 100 |
(2) global关键字
- 一般情况下,在函数内无法修改全局变量的值
1 | num = 100 |
- 使用
global
关键字可以在函数内部声明变量为全局变量, 如下所示
1 | num = 100 |
2.函数进阶
2.1多返回值
1 | def test(): |
- 支持return不同类型的数据
1 | def test(): |
2.2.关键字参数
函数调用时通过“键=值”形式传递参数.
1 | def user_info(name, age, gender): |
2.3.缺省参数
也叫默认参数,用于定义函数,为参数提供默认值,调用函数时可不传该默认参数的值
所有位置参数必须出现在默认参数前,包括函数定义和调用
当调用函数时没有传递参数, 就会使用默认是用缺省参数对应的值.
函数调用时,如果为缺省参数传值则修改默认参数值, 否则使用这个默认值
1 | def user_info(name, age, gender='男'): |
2.4.不定长参数
也叫可变参数. 用于不确定调用的时候会传递多少个参数(不传参也可以)的场景.
位置传递
- 以*号标记一个形式参数,以元组的形式接受参数
- 传进的所有参数都会被args变量收集,它会根据传进参数的位置合并为一个元组(tuple),args是元组类型
1 | def user_info(*args): |
关键字传递
关键字不定长传递以**号标记一个形式参数,以字典的形式接受参数
参数是“键=值”形式的形式的情况下, 所有的“键=值”都会被kwargs接受, 同时会根据“键=值”组成字典.
1 | def user_info(**kwargs): |
lambda匿名函数(未学习)
13数据容器
根据特点的不同可分为5类:列表(list)、元组(tuple)、字符串(str)、集合(set)、字典(dict)
13.1. list
1 | # 定义列表 |
列表的下标(索引)
我们可以使用下标索引从列表中取出特定位置的数据
- 正向索引
从前往后的方向,从0开始,依次递增
- 反向索引
从-1开始,依次递减
使用方式 | 作用 |
---|---|
列表.append(元素) | 向列表中追加一个元素 |
列表.extend(容器) | 将数据容器的内容依次取出,追加到列表尾部 |
列表.insert(下标, 元素) | 在指定下标处,插入指定的元素 |
del 列表[下标] | 删除列表指定下标元素 |
列表.pop(下标) | 删除列表指定下标元素 |
列表.remove(元素) | 从前向后,删除此元素第一个匹配项 |
列表.clear() | 清空列表 |
列表.count(元素) | 统计此元素在列表中出现的次数 |
列表.index(元素) | 查找指定元素在列表的下标 找不到报错ValueError |
len(列表) | 统计容器内有多少元素 |
查询元素
查找某元素的下标
查找指定元素在列表的下标,如果找不到,报错ValueError
语法:列表.index(元素)
1 | my_list = ["李白", "章北海", "罗辑", "杜甫"] |
插入元素
在指定的下标位置,插入指定的元素
语法:列表.insert(下标, 元素)
1 | my_list = ["李白", "章北海", "罗辑"] |
追加元素
将指定元素,追加到列表的尾部
语法一:列表.append(元素)
1 | my_list = ["李白", "章北海", "罗辑"] |
语法二:列表.extend(其它数据容器)
将其它数据容器的内容取出,依次追加到列表尾部
1 | my_list_1 = ["李白", "章北海"] |
删除元素
语法一:del 列表[下标]
1 | my_list = ["李白", "章北海", "罗辑"] |
语法二:列表.pop(下标)
1 | my_list = ["李白", "章北海", "罗辑"] |
语法三:列表.remove(元素)
删除某元素在列表中的第一个匹配项
1 | my_list = ["李白", "章北海", "罗辑", "李白"] |
清空列表内容
- 语法:列表.clear()
1 | my_list = ["李白", "章北海", "罗辑"] |
统计某元素在列表内的数量
- 语法:列表.count(元素)
1 | my_list = ["李白", "章北海", "罗辑", "李白"] |
统计列表内有多少元素
- 语法:len(列表)
1 | my_list = ["李白", "章北海", "罗辑", "李白"] |
列表的遍历
1 | my_list = [1,2,3,4] |
1 | my_list = [1, 2, 3, 4] |
13.2元组(tuple)
元组同列表一样,但一旦定义完成,就不可修改
(1) 基本格式
1 | # 定义元组 |
元组只有一个数据,这个数据后面要添加逗号,否则不是元组
1 | my_tuple = ("观止") |
方法 | 作用 |
---|---|
元组.index(元素) | 查找某个数据,如果数据存在返回对应的下标,否则报错 |
元组.count(元素) | 统计某个数据在当前元组出现的次数 |
len(元组) | 统计元组内的元素个数 |
13.3 字符串(str)
字符串是字符的容器,一个字符串可以存放任意数量的字符。
1 | name = "dreamxiaoshen" |
字符串的常用操作
操作 | 说明 |
---|---|
字符串[下标] | 根据下标索引取出特定位置字符 |
字符串.index(字符串) | 查找给定字符的第一个匹配项的下标 |
字符串.replace(字符串1, 字符串2) | 将字符串内的全部字符串1,替换为字符串2 不会修改原字符串,而是得到一个新的 |
字符串.split(字符串) | 按照给定字符串,对字符串进行分隔 不会修改原字符串,而是得到一个新的列表 |
字符串.strip() 字符串.strip(字符串) | 移除首尾的空格和换行符或指定字符串 |
字符串.count(字符串) | 统计字符串内某字符串的出现次数 |
len(字符串) | 统计字符串的字符个数 |
1.查找元素
查找特定字符串的下标索引值
语法:字符串.index(字符串)
1 | name = "dreamxiaoshen" |
2.替换元素
将字符串内的全部:字符串1,替换为字符串2
语法:字符串.replace(字符串1,字符串2)
1 | name = "dreamxiaoshen" |
不是修改字符串本身,而是得到了一个新字符串
3.分割元素
按照指定的分隔符字符串,将字符串划分为多个字符串,并存入列表对象中
语法:字符串.split(分隔符字符串)
1 | name = "xiaoshen,study,20" |
字符串本身不变,而是得到了一个列表对象
4. 规整操作
去前后空格以及换行符
语法一:字符串.strip()
1 | name = " xiaoshen " |
去前后指定字符串
语法二:字符串.strip(字符串)
1 | name = "20xiaoshen20" |
字符串本身不变,而是得到了一个新字符串
5.统计操作
统计字符串中某字符串的出现次数
语法一:字符串.count(字符串)
1 | name = "20xiaoshen20" |
统计字符串的长度
语法二:len(字符串)
1 | name = "20xiaoshen 20" |
13.4.数据容器(序列)的切片
1.基本用法
用法
起始下标可以省略,省略从头开始
结束下标可以省略,省略到尾结束
步长可以省略,省略步长为1(可以为负数,表示倒序执行)
用法一:
1 | my_list = [1, 2, 3, 4, 5] |
用法二:
1 | my_tuple = (1, 2, 3, 4, 5) |
用法三:
1 | my_list = [1, 2, 3, 4, 5] |
用法四:
1 | my_str = "12345" |
用法五:
1 | my_list = [1, 2, 3, 4, 5] |
注:
这个操作对列表、元组、字符串是通用的
此操作不会影响序列本身,而是会得到一个新的序列(列表、元组、字符串)
起始位置,结束位置,步长(正反序)都是可以自行控制的
13.5.集合(set)
不支持元素的重复(自带去重功能)、并且内容无序
(1) 基本格式
1 | # 定义集合 |
以大括号 {} 作为标识
集合内每一个元素之间用, 逗号隔开
集合可以一次存储多个数据,且可以为不同的数据类型,支持嵌套
使用示例:
1 | my_set = {"断桥圆月", True, "断桥圆月"} |
去重且无序
(2) 集合的遍历
集合不支持下标索引,所以也就不支持使用while。
因为集合是无序的,所以集合不支持下标索引访问
1 | my_set = {"断桥圆月", True, "断桥圆月"} |
(3) 集合的常用操作
操作 | 说明 |
---|---|
集合.add(元素) | 集合内添加一个元素 |
集合.remove(元素) | 移除集合内指定的元素 |
集合.pop() | 从集合中随机取出一个元素 |
集合.clear() | 将集合清空 |
集合1.difference(集合2) | 得到一个新集合,内含2个集合的差集 原有的2个集合内容不变 |
集合1.difference_update(集合2) | 在集合1中,删除集合2中存在的元素 集合1被修改,集合2不变 |
集合1.union(集合2) | 得到1个新集合,内含2个集合的全部元素 原有的2个集合内容不变 |
len(集合) | 得到一个整数,记录了集合的元素数量 |
1. 增加元素
集合本身被修改,将指定元素,添加到集合内
语法:集合.add(元素)
1 | my_set = {"断桥圆月", True, "断桥圆月"} |
2. 移除元素
集合本身被修改,将指定元素,从集合内移除
语法一:集合.remove(元素)
1 | my_set = {"断桥圆月", True, "断桥圆月"} |
从集合中随机取出一个元素,同时集合本身被修改,元素被移除
语法二:集合.pop()
1 | my_set = {"社区医院", True} |
清空集合,集合本身被清空
语法三:集合.clear()
1 | my_set = {"断桥圆月", True} |
3. 两集合操作
取出集合1和集合2的差集(集合1有而集合2没有的),得到一个新集合,集合1和集合2不变
语法一:集合1.difference(集合2)
1 | my_set_1 = {1, 2} |
对比集合1和集合2,在集合1内,删除和集合2相同的元素,集合1被修改,集合2不变
语法二:集合1.difference_update(集合2)
1 | my_set_1 = {1, 2} |
将集合1和集合2组合成新集合(去重),集合1和集合2不变
语法三:集合1.union(集合2)
1 | my_set_1 = {1, 2} |
4.集合长度
查看集合的元素数量,统计集合内有多少元素
语法四:len(集合)
1 | my_set = {1, 3} |
13.6字典、映射(dict)
Python中字典和生活中字典十分相像
(1) 基本格式
1 | # 定义字典 |
使用{}存储原始,每一个元素是一个键值对
每一个键值对包含Key和Value(用冒号分隔)
键值对之间使用逗号分隔
Key和Value可以是任意类型的数据(key不可为字典)
Key不可重复,重复会对原有数据覆盖
使用示例:
1 | my_dict = {"观止": 99, "李白": 120, "观止": 110} |
(2) 数据的获取
字典同集合一样,不可以使用下标索引取值
字典可以通过Key值来取得对应的Value
1 | my_dict = {"李白": 120, "观止": 110} |
字典的Key和Value可以是任意数据类型(Key不可为字典),即字典是可以嵌套的
1 | my_dict = { |
字典不支持下标索引,同样不可以用while循环遍历
1 | my_dict = {"李白": 120, "断桥圆月": 110} |
(3) 字典的常用操作
操作 | 说明 |
---|---|
字典[Key] | 获取指定Key对应的Value值 |
字典[Key] = Value | 添加或更新键值对 |
字典.pop(Key) | 取出Key对应的Value并在字典内删除此Key的键值对 |
字典.clear() | 清空字典 |
字典.keys() | 获取字典的全部Key,可用于for循环遍历字典 |
len(字典) | 计算字典内的元素数量 |
1. 新增元素
字典被修改,新增了元素
如果key不存在字典中执行上述操作,就是新增元素
语法:字典[Key] = Value
1 | my_dict = {"李白": 120, "观止": 110} |
2. 更新元素
字典被修改,元素被更新
字典Key不可以重复,所以对已存在的Key执行上述操作,就是更新Value值
语法:字典[Key] = Value
1 | my_dict = {"李白": 120, "观止": 110} |
3. 删除元素
获得指定Key的Value,同时字典被修改,指定Key的数据被删除
语法:字典.pop(Key)
1 | my_dict = {"李白": 120, "观止": 110} |
4. 清空字典
字典被修改,元素被清空
语法:字典.clear()
1 | my_dict = {"李白": 120, "观止": 110} |
5. 获取全部的key
得到字典中的全部Key
语法:字典.keys()
1 | my_dict = {"李白": 120, "观止": 110} |
6.计算字典内键值对数量
得到一个整数,表示字典内元素(键值对)的数量
语法:len(字典)
1 | my_dict = {"李白": 120, "观止": 110} |
简单分类
是否支持下标索引
支持:列表、元组、字符串 - 序列类型
不支持:集合、字典 - 非序列类型
是否支持重复元素:
支持:列表、元组、字符串 - 序列类型
不支持:集合、字典 - 非序列类型
是否可以修改
支持:列表、集合、字典
不支持:元组、字符串
(2) 特点对比
列表 | 元组 | 字符串 | 集合 | 字典 | |
---|---|---|---|---|---|
元素数量 | 支持多个 | 支持多个 | 支持多个 | 支持多个 | 支持多个 |
元素类型 | 任意 | 任意 | 仅字符 | 任意 | Key:Value Key:除字典外任意类型 Value:任意类型 |
下标索引 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
重复元素 | 支持 | 支持 | 支持 | 不支持 | 不支持 |
可修改性 | 支持 | 不支持 | 不支持 | 支持 | 支持 |
数据有序 | 是 | 是 | 是 | 否 | 否 |
使用场景 | 可修改、可重复的一批数据记录场景 | 可修改、可重复的一批数据记录场景 | 不可修改一串字符的记录场景 | 不可重复的数据记录场景 | 以Key检索Value的数据记录场景 |
14.文件操作
未学习
15.异常
15.1.什么是异常
程序运行的过程中出现了错误
定义:在程序运行中,检测到一个错误,程序中止运行并且出现了一些错误的提示,也称作BUG
避免程序中止,提前准备处理可能出现的异常
在真实工作中, 我们肯定不能因为一个小的BUG就让整个程序全部奔溃,而是对BUG进行提醒, 整个程序继续运行
三.如何捕获异常
在可能出现异常的地方,做好提前准备,当真的出现异常的时候,可以有后续手段。
(1) 捕获常规异常
基本语法:
1 | try: |
(2) 捕获特定异常
如果尝试执行的代码的异常类型和要捕获的异常类型不一致,则无法捕获异常。
基本语法:
1 | try: |
例如:
捕获未定义变量产生的错误
1 | try: |
同样的代码却无法捕获处理找不到文件异常
1 | try: |
(3) 捕获多个异常
格式一:当待捕获异常名为Exception可以捕获所有类型异常,作用与(1)一致
例如:
1 | try: |
格式二:把要捕获的异常类型的名字,放到except 后,并使用元组的方式进行书写。
基本格式:
1 | try: |
使用示例:
1 | # 示例一: |
1 | # 示例二: |
指定的两种异常都能捕获,未指定的无法捕获到
(4) 其他用法
异常描述信息存贮在别名中,可以通过打印别名获取
使用示例:
1 | try: |
使用示例:
出现异常,打印结果与(4.2)一致
1 | try: |
无异常
1 | try: |
15.2.异常finally
finally表示的是无论是否异常都要执行的代码
使用示例:
之前提过,如果open文件却一直未close且程序未中止,将一直占用文件无法操作
如果打开文件后发生异常,未close也将导致一直占用,因此可选择在finally中close
1 | global f |
15.3.异常的传递
异常是具有传递性的向上一级抛出
当函数调用链中出现异常,如果所有函数都没有捕获异常的时候, 程序就会报错
利用异常具有传递性的特点, 当我们想要保证程序不会因为异常崩溃的时候, 就可以在主函数中设置异常捕获, 由于无论在整个程序哪里发生异常, 最终都会传递到主函数中, 这样就可以确保所有的异常都会被统一捕获
16.包和模块
16.1模块
(1) 什么是模块
一个Python文件,以.py 结尾,能定义函数,类和变量,也能包含可执行的代码
作用:我们可以认为不同的模块就是不同工具包,每一个工具包中都有各种不同的工具(如函数)供我们使用进而实现各种不同的功能.
(2) 模块的导入
模块在使用之前需要先导入正在开发的文件
导入语法:
1 | [from 模块名] import [模块|类|变量|函数|*] [as 别名] |
常用的组合形式如:
import 模块名
from 模块名 import 类、变量、方法等
from 模块名 import *
import 模块名 as 别名
from 模块名 import 功能名 as 别名
(2.1) 用法一
1 | 基本语法: |
1 | # 导入时间模块 |
(2.2) 用法二
基本语法
1 | # 导入 |
使用示例:
1 | # 导入时间模块中的sleep方法 |
效果图与(2.1)一致
(2.3) 用法三
基本语法
1 | # 导入一:模块定义别名 |
使用示例一:
1 | # 本名time将不可用 |
使用示例二:
1 | # 本名sleep将不可用 |
效果图与(2.1)一致
(2.4) 用法四
基本语法
1 | # 导入 |
使用示例:
1 | # 导入时间模块中的全部功能 |
17.面向对象
一.什么是面向对象
万物皆对象
现实世界的事物都有属性和行为,可在程序中抽离为类来描述现实世界的事物属性和行为。
使用类充当程序内现实事物的“设计图纸”,基于图纸(类)生产实体(对象),由对象做具体的工作,称之为:面向对象编程
二.类与对象
使用类封装属性,基于类创建出一个个的对象来使用
(1) 基本语法
1 | # 创建类 |
class:关键字,表示要定义类了
类的属性:定义在类中的变量(成员变量) -> 事物的属性
类的行为:定义在类中的函数(成员方法) -> 事物的行为
(2) 使用示例
设计表格即设计类(class):
1 | class Student: |
打印表格即创建对象:
1 | stu_1 = Student() # 一张 |
填写表格即使用对象(为属性赋值):
1 | stu_1.name = "李白" |
(3) 成员变量和成员方法
(3.1) 成员变量
- 定义在类内部的变量称之为成员变量,用法与正常变量一致。
(3.2) 成员方法
定义在类内部的函数称之为方法,与函数存在细微区别。
1 | #函数 |
self
关键字在成员方法定义的时候必须填写,表示类对象自身
在方法内部,想要访问类的成员变量,必须使用self
1 | class Student: |
当我们使用对象调用方法的时,self会自动被python传入,尽管在参数列表中,传参的时候可以忽略它
1 | #定义 |
(4) 构造方法
通过传参的形式快速对属性赋值
正常情况下,为对象的属性赋值需要依次进行
1 | # 定义类 |
在类可以使用:init()方法,即构造方法,快速为对象赋值。
1 | # 定义类 |
在创建类对象(构造类)的时候,会自动执行,将传入参数自动传递给__init__方法使用。
构造方法也是成员方法,定义时也需要在参数列表中提供:self
变量定义在构造方法内部,如果要成为成员变量,需要用self来表示,例如self.name
使用了构造方法,创建对象时必须传参否则会报错
(5) 魔术方法
Python类内置的类方法,各自有各自特殊的功能
魔术方法非常多,我们学习几个常用的即可。
方法 | 功能 |
---|---|
init |
构造方法,可用于创建类对象的时候设置初始化行为 |
str |
字符串方法,用于实现类对象转字符串的行为 |
lt |
用于2个类对象进行小于(<)或大于(>)比较 |
le |
用于2个类对象进行小于等于(<=)或大于等于(>=)比较 |
eq |
用于2个类对象进行相等(==)比较 |
(5.1)__str__
方法
当直接打印类对象时,打印的是对象的内存地址,用处不大。
1 | class Student: |
我们可以通过__str__
方法,自定义控制打印类对象时输出的内容。
1 | class Student: |
(5.2)__lt__
方法
直接对2个对象进行比较是不可以的,会报错。
1 | class Student: |
在类中实现__lt__
方法即可完成:小于符号 和 大于符号 2种比较
1 | class Student: |
(5.3) __le__
方法
在类中实现__le__方法即可完成:小于等于符号 和 大于等于符号 2种比较,否则会报错
1 | class Student: |
(5.4) __eq__
方法
不实现__eq__
方法,对象之间可以比较,但是是比较内存地址,但是不同对象==比较一定是False结果。
1 | class Student: |
实现了__eq__
方法,就可以按照自己的想法来决定2个对象是否相等了。
1 | class Student: |
三.三大特性
面向对象包含3大主要特性:封装,继承,多态
(1) 封装
将现实世界事物的属性和行为在类中描述为成员变量和成员方法,完成程序对现实世界事物的描述
现实世界中的事物,有属性和行为。但是不代表这些属性和行为都是开放给用户使用的
(1.1) 私有成员
在类中提供仅供内部使用的属性和方法,无法被对象调用
基本语法:
私有成员变量:变量名以__开头(2个下划线)
私有成员方法:方法名以__开头(2个下划线)
1 | class Student: |
仅在成员内部可以使用
1 | class Student: |
(2) 继承
一个类继承另外一个类的所有成员变量和成员方法(不含私有)
(2.1) 单继承
基本语法:
1 | class 类名(父类名): |
基本使用:
1 | # 待继承的类 |
(2.2) 多继承
一个类也可以继承多个类
多个父类中,如果有同名的成员,默认以继承顺序(从左到右)为优先级。即:后继承的被先继承的覆盖
基本语法:
1 | class 类名(父类1,父类2,...,父类N): |
使用示例:
1 | class Phone: |
(2.3) 复写
子类继承父类的成员属性和成员方法后,如果对其“不满意”,那么可以进行复写。即:在子类中重新定义同名的属性或方法。
一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
1 | class Phone2021: |
如果需要使用被复写的父类的成员,只能在子类内通过如下方式调用父类的同名成员:
方式一:使用父类名调用
1 | 使用成员变量:父类名.成员变量 |
方式二:使用super()调用
1 | 使用成员变量:super().成员变量 |
使用示例:
1 | class Phone2021: |
(3) 多态
多种状态,即完成某个行为时,使用不同的对象会得到不同的状态
多态常作用在继承关系上,函数(方法)形参声明接收父类对象,实际传入父类的子类对象进行工作,即
- 以父类做定义声明
- 以子类做实际工作
- 用以获得同一行为, 不同状态
(3.1) 抽象类(接口)
抽象类就好比定义一个标准,包含了一些抽象的方法,要求子类必须实现
抽象类:包含抽象方法的类
抽象方法:没有具体实现的方法(只含pass)称之为抽象方法
pass
是占位语句,用来保证函数(方法)或类定义的完整性,表示无内容,空的意思
多用于做顶层设计(设计标准),以便子类做具体实现。是对子类的一种软性约束,要求子类必须复写(实现)父类的一些方法
并配合多态使用,获得不同的工作状态。
18.类型注解
一.为什么需要类型注解
在代码中提供数据类型的注解(显式的说明),使用时能获得相关提示
帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示
显示声明时,pycharm确定这个对象是list类型,使用时能有对应提示
没有声明具体类型时,使用不会有任何相关提示
帮助开发者自身对变量进行类型注释(备注),后面调用不易出错
(1) 语法格式
变量名: 数据类型 = 数值
Python中类型注解仅仅起到提示作用,没有其他语言那么严格
Python解释器不会根据类型注解对数值做验证和判断,无法对应上也不会导致错误
(2) 基础类型
整数类型注解
1 | var_1: int = 1314 |
浮点数类型注解
1 | var_2: float = 5.21 |
布尔类型注解
1 | var_3: bool = True |
字符串类型注解
1 | var_4: str = "hhybd" |
(3) 类对象
1 | # 定义学生类 |
(4) 数据容器
列表类型注解
方式一:
1 | my_list: list = [1, 2, 3] |
方式二,list[基础类型]:
1 | my_list: list[int] = [1, 2, 3] |
元组类型注解
方式一:
1 | my_tuple: tuple = (1, 2, 3) |
方式二,元组类型需要将每一个元素都标记出来:
1 | my_tuple: tuple[str, int, bool] = ("bd", 521, True) |
集合类型注解
方式一:
1 | my_set: set = {1, 2, 3} |
方式二,set[基础类型]:
1 | my_set: set[int] = {1, 2, 3} |
字典类型注解
方式一:
1 | my_dict: dict = {"hhbdy": 250} |
方式二,dict[键类型,值类型]:
1 | my_dict: dict[str, int] = {"hhbdy": 250} |
字符串类型注解
1 | my_str: str = "hhybd" |
(5) 其他语法格式
在注释中进行类型注解
语法格式:
1 | type:类型 |
使用示例:
1 | stu = Student() # type:Student |
三.函数(方法)的类型注解
标注形参和返回值数据类型
类型注解仅仅起到提示作用
(1) 形参注解
语法格式:
1 | def 函数方法名(形参名1:类型,形参名2:类型): |
(2) 返回值注解
语法格式:
1 | def 函数方法名(形参名1:类型,形参名2:类型) -> 返回值类型: |
使用示例:
1 | def add(x: int, y: int) -> int: |
四.Union类型
联合类型注解,在变量注解、函数(方法)形参和返回值注解中均可使用
需要导包使用
当数据类型不唯一时基本格式无法满足要求,此时便可使用Union类型
使用示例,Union[类型,类型]:
在变量中:
1 | from typing import Union |
在函数中:
1 | from typing import Union |
19.高级
一.闭包
可以保存函数内变量,不会随着函数调用完而销毁
(1) 基本定义
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。
使用示例:
1 | # 1.在函数嵌套(函数中定义函数)的前提下 |
(2) 修改外部函数变量的值
在闭包函数(内部函数中)想要修改外部函数的变量值,必须用nonlocal声明这个外部变量
1 | # 1.在函数嵌套(函数中定义函数)的前提下 |
(3) 小结
优点:
无需定义全局变量即可实现通过函数,持续的访问、修改某个值
闭包使用的变量于所在的函数内,难以被错误的调用修改,可使变量更安全不易被恶意行为修改
缺点:
由于内部函数持续引用外部函数的值,所以会导致这一部分内存空间不被释放,一直占用内存(额外的内存占用)
二.装饰器
也是一种闭包,可在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能
(1) 基本使用
装饰器就是把一个函数当做参数传递给闭包中的外部函数,同时在内部函数中使用这个函数,并给他添加新的功能。
外部函数只能有一个参数,往往是被装饰的函数
内部函数可以根据被装饰的函数提供多个参数以及返回值
1 | # 定义一个装饰器 |
(2) 语法糖使用
可直接在需要被装饰的函数上加@装饰器名字,解释器碰到时会自动执行装饰过程,简化使用流程
1 | # 定义一个装饰器 |
(3) 多个装饰器使用
将装饰器都写在需要被装饰的函数上面即可
谁离被装饰的函数最近,谁就先去装饰函数
1 | # 定义装饰器1 |
(4) 带参数的装饰器
需要再增加一层函数嵌套来接收传递的参数
1 | # 第一层:用于接收装饰器传递的参数 |
(5) 类装饰器(了解即可)
一个类里面一旦实现了__call__方法,那么这个类创建的对象就是一个可调用对象,可以像调用函数一样进行调用
1 | # 定义类 |
类装饰器装饰函数的功能通过call方法实现
1 | # 定义类装饰器 |
三.property属性
把类中的一个方法当作属性进行使用,简化开发
例如我们如果想获取和修改私有属性必须通过类方法修改,示例代码:
1 | class Person: |
通过使用如下两种方式可简化上述代码的使用
(1) 装饰器方式使用
@property表示把方法当作属性使用,表示当获取属性时执行下面修饰的方法
property修饰的方法名要与属性名一样
@方法名.setter表示把方法当作属性使用,表示当设置属性值时会执行下面修饰的方法
1 | class Person: |
(2) 类属性方式使用
property的参数说明:
属性名 = property(获取值方法,设置值方法)
第一个参数:获取属性时要执行的方法
第二个参数:设置属性时要执行的方法
1 | class Person: |
四.上下文管理器
由实现了__enter__()和__exit__()方法的类创建的对象
在文件操作篇提到过使用with语句可以自动调用关闭文件操作,即使出现异常也会自动调用关闭文件操作。
1 | with open("guanzhi.txt", "w") as f: |
使用with语句简化操作是建立在上下文管理器上的,open函数创建的f文件对象就是一个上下文管理器对象
__enter表示上文方法,需要返回一个操作文件对象
__exit__表示下文方法,with语句执行完成会自动执行,即使出现异常也会执行该方法
1 | # 定义一个File类 |
五.深拷贝浅拷贝
开辟新的内存空间接收变量
调用id()可获得变量的内存地址
(1) 浅拷贝
(1.1) 可变类型浅拷贝
使用copy函数进行浅拷贝,只对可变类型的第一层对象进行拷贝
对拷贝的对象开辟新的内存空间进行存储
不会拷贝对象内部的子对象
1 | import copy |
(1.2) 不可变类型浅拷贝
不可变类型进行浅拷贝不会给拷贝的对象开辟新的内存空间,只是拷贝了这个对象的引用
1 | a = (1, 2, 3) |
(2) 深拷贝
保障数据的独立性
(2.1) 可变类型深拷贝
使用deepcopy函数进行深拷贝,会对可变类型内每一层可变类型对象进行拷贝,开辟新的内存空间进行存储
1 | import copy |
(2.2) 不可变类型深拷贝
不可变类型进行深拷贝不会给拷贝的对象开辟新的内存空间,只是拷贝了这个对象的引用
1 | a = (1, 2, 3) |
六.eval函数
eval()函数可将字符串当成有效的表达式来求值并返回计算结果
1 | # 基本的数学运算 |
注意事项:开发时千万不要使用eval直接转换input的结果
用户可能恶意输入有危害的终端指令
1 | input_str = input() # 输入 __import__('os').system('rm -rf /*') |