? Python是人与计算机交流的语言,编程语言的一种,是面向对象语言
? 程序设计原则:KISS原则 – 简洁胜于复杂
? 语法简洁明了,实现代码短,模块众多
? web应用开发
? 人工智能
? 网络爬虫
? 游戏开发(2D游戏)
? 可视化,自动化脚本
? 1.交互式执行方式(及时给出响应,代码不能保存):
? 不需要创建脚本文件,直接通过Python解释器的交互模式来编写代码
? 2.文件式执行方式(代码可以永久保存,但不能及时给出回应):
? 新建一个.py文件,代码在文件中执行
? 在浏览文档时,如果发现参数旁边有方括号 []
,说明这是一个可选参数,相当于是这个函数或者方法的高级应用,如果给它赋值的话,它会有新的特性出现
? 变量就是在存储数据时,当前数据所在的内存地址的名字,变量的作用即标识数据
? 在程序中,数据都是临时存储在内存当中,为了更快速的查找或使用这个数据,通常给它定义一个名称,这个名称就是变量名
变量的赋值语法:变量名 = 值
? 单变量赋值
name = "姓名"
? 多变量赋值
name,age,hobby = "姓名",100,"AI"
name = "姓名"
age = 100
hobby = "AI"
a = b = c = 1
变量的命名规范:
查看Python关键字的代码:
import keyword
print(keyword.kwlist)
Python中的关键字
['False', 'None', 'True', 'and', 'as', 'assert', 'async', 'await', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'nonlocal', 'not', 'or', 'pass', 'raise', 'return', 'try', 'while', 'with', 'yield']
4.变量里有:变量名,变量的值,内存地址
? 注意: 如果某个变量要作为临时变量或者无关紧要的变量使用,可以直接用下划线 _ 当作变量名
? 用于查看变量或对象的内存地址
? 在程序运行时,系统会自动把程序中的变量,数据临时存储到内存当中,内存会自动的分配空间,而变量名就是指向那块空间的名字,每一次运行,系统分配的空间位置不同,内存地址不同
a = 9
print(id(a))
? 单行注释采用 # 开头
? PyCharm
注释快捷键:CTRL + /
? PyCharm
快速格式化代码:CTRL + ALT + L
数值类型:int()
– 整型;
float()
– 浮点型
a,b = 13,-12
c,d = 3.46,-67.4
布尔类型:True
– 真;False
– 假
str()
– 字符串
a = 'a'
b = "b"
c = '''c'''
list()
– 列表
a = 67
b = ["a",17,"68",-76,4.31,'b',a]
tuple()
– 元组
a = 67
b = ("a",17,"68",-76,4.31,'b',a)
set()
– 集合
a = 67
b = {"a",17,"68",-76,4.31,'b',a}
dict()
– 字典
? 键值对:键:值 – 左面为键,右面为值,键可以看作是值的名字
a = 185
b = {"name":"姓名","age":29,"hobby":"AI","height":a}
? 注意: 1. 整型中并不包含小数
? 2. 若 ''
所包裹的内容之中同样有 ''
那么应使用 " "
或 ''' '''
包裹,反之亦然
? 3. 字符串,列表;元组;集合;字典统称为序列,它们都是容器,字符串属于半个容器
? 4. 列表;元组;集合中的元素分布内容一致,但字典中的元素为键值对,一个键值对为一个数据,不是两个
? 5.Python是弱类型语言,可以自动的去识别数据类型,不需要特意定义
? 类型转换是一种强制型的转换,要在进行转换的内容的前面加上类型标识
类型标识(函数) | 说明 |
---|---|
int(x) | 将x 转换为整数 |
float(x) | 将x 转换为浮点数 |
str(x) | 将x 转换为字符串 |
eval(str) | 将字符串中的数据转换成Python表达式的原本类型 |
tuple(s) | 将序列s 转换为一个元组 |
list(s) | 将序列s 转换为一个列表 |
? 注意: 1.像整数的字符串可以转换为整数,也可以转换为浮点数
? 2.像小数的字符串可以转换为浮点数,但不可以直接转换为整数
? 3.任何类型都不可以转换为字典
? 4.布尔类型可以转换为整型 – True
为1,Flase
为0,浮点型和字符串,但不能转换为序列
? 5.字典转换后只会保留键
? 6.类型转换要符合实际!!!
a = "123"
b = int(a)
print(b)
a = 15
print(float(str(a)))
print(int(True))
print(float(True))
print(str(True))
a = {"zh":185,"姓名":183}
print(list(a))
type()
函数:? 查看数据类型
a = 23.54
b = int(a)
print(b,type(b))
a = 34.89
print(int(a),type(a))
? 把数据给到程序中的过程叫做输入
? 输入函数:input()
input("请输入你的姓名:")
name = input("请输入你的姓名:")
? 注意: 1. input()
函数括号里的信息仅用作提示,需要输入的信息是写在控制台上的
? 2.在Python中,input()
会自动把用户输入的数据当作字符串处理
print(int(float(input())))
格式化符号 | 转换 |
---|---|
%s | 字符串 |
%d | 整数 |
%f | 浮点数,默认为小数点后六位,%.几f – 用于保留小数点后几位(会自动四舍五入) |
%u | 无符号十进制整数 |
%o | 八进制整数 |
%x | 十六进制整数 |
%e | 小数点后面六位有效数字,以指数形式输出实数 |
%g | 根据大小自动选%f 或%e 格式,且不输出无意义的零 |
转义符号 | 作用 |
---|---|
\n | 换行符 |
\t | 制表符(四个空格) |
\r | 顶格,将光标位置移动到本行开头 |
\b | 退格,将光标位置向前移动一位 |
\ | 续写符 |
\' | 单引号转义 |
\" | 双引号转义 |
? 注意: 在字符串前面加上 r
表示取消转义
print(r"wenjain1/f/df/ad")
? 把数据从程序中取出的过程叫做输出
? 输出函数:print()
? 作用:用于打印,输出,将括号里面的内容输出到控制台上,是Python中最常见的函数
? print()
不仅可以输出一个对象,也可以输出多个对象,中间用 , 隔开
a = 10
print(a)
age = 19
print("你的年龄:",age)
?
print()
的语法格式:
print(变量/值,sep = ' ',end = '\n',file = sys.stdout)
? sep
: 用来间隔多个对象,用作变量间的隔断,默认值是一个空格
? end
: 用来设定以什么结尾,影响下一次输出的位置,默认值是换行符\n
? file
: 要写入的文件对象
name,height,age,hobby = "龙泽", "1.85m", 19, "人工智能"
print(name,height,age,hobby,sep=" | ",end="\t")
?
print()
的输出格式:
? 1. 普通输出:用逗号去隔开想输出的内容:
name = "qiao_yue"
print("你的名字:",name," 才怪")
? 2. 使用%占位符输出:
name = "qiao_yue"
print("你的名字:%s 才怪"%name)
age = 19
print("你的年龄:%d ~~~"%age)
height = 110.5
print("你的体重是:%f ~~~"%height) #110.500000
print("你的体重是:%.1f ~~~"%height) #110.5
? 多个%占位符输出
name = "姓名"
age = 29
height = 110.5
print("你的姓名:%s 你的年龄:%d 你的体重:%f"%(name,age,height))
? 注意: 1. %s
可以用于任何类型,是通用占位符
? 2. %d
用于填充int
类型,填充小数时会进行强制类型转换,只保留整数,有损精度
? 3. %f
用于填充浮点类型,填充整数时会进行强制类型转换,结尾用0填充
? 4. 只有一个%占位符占位时,就用一个变量去填充,多写少写都会报错
? 5. %占位符受类型的限制,但变量,对象都可以进行填充
? 3. “{}”.format()输出:
name = "姓名"
age = 19
print("你的年龄:{} ~~~".format(age))
? 多个"{}".format()输出
name = "姓名"
age = 19
height = 110.5
print("你的姓名:{} 你的年龄:{} 你的体重:{}".format(name,age,height))
? 遇到要保留小数时 – "{:.几f}".format()
name = "姓名"
age = 19
height = 110.5867
print("你的姓名:{} 你的年龄:{} 你的体重:{:.2f}".format(name,age,height))
? 注意: 1.只有一个{}占位时,就用一个变量去填充,后面多写变量也不会有显示,但少写会报错
? 2. format()
没有类型的限制,变量,对象都可以进行填充
? 4. f"{}"
输出:
age = 19
print(f"你的年龄:{age} ~~~")
? 多个f"{}"
输出
name = "姓名"
age = 19
height = 110.5
print(f"你的姓名:{name} 你的年龄:{age} 你的体重:{height}")
? 遇到要保留小数时 – f"{变量/对象:.几f}"
name = "qiao_yue"
age = 19
height = 110.5867
print(f"你的姓名:{name} 你的年龄:{age} 你的体重:{height:.2f}")
? 注意: 1. f"{}"没有类型的限制,变量,对象都可以进行填充
? 算数运算符
符号 | 描述 |
---|---|
+ | 加 |
- | 减 |
* | 乘 |
/ | 除 |
// | 整除(自动四舍五入) |
% | 取余(没有四舍五入) |
** | 乘方(幂运算) |
() | 优先级 |
? 注意: 1.先乘方,后乘除,最后加减,有括号的先算括号里的,同级从左往右算
? 2.余数没有负数,除不尽的都余1,且取余时不能将任何数字除以0,不然会报错
? 赋值运算符
符号 | 描述 |
---|---|
= | 赋值 |
? 复合赋值运算符
符号 | 描述 |
---|---|
+= | 加法赋值运算符 |
-= | 减法赋值运算符 |
*= | 乘法赋值运算符 |
/= | 除法赋值运算符 |
//= | 整除赋值运算符 |
%= | 取余赋值运算符 |
**= | 乘方赋值运算符 |
? 注意: 1.先运算,后赋值
a /= 1
a = a / 1
a **= 5
a = a ** 5
? 比较运算符
符号 | 描述 |
---|---|
== | 相等,若左右两边结果相等,则条件为真(True),反之,结果为假(False) |
!= | 不等于,若左右两边结果不相等,则条件为真(True),反之,结果为假(False) |
> | 大于,若左边结果大于右边,则条件为真(True),反之,结果为假(False) |
>= | 大于等于,若左边结果大于或等于右边,则条件为真(True),反之,结果为假(False) |
< | 小于,若左边结果小于右边,则条件为真(True),反之,结果为假(False) |
<= | 小于等于,若左边结果小于或等于右边,则条件为真(True),反之,结果为假(False) |
? 逻辑运算符
符号 | 逻辑表达式 | 描述 | 实例 |
---|---|---|---|
and | a and b | 若有一边为假,都为假,两边为真,才为真 | True and False,返回False |
or | a or b | 若有一边为真,都为真,两边为假,才为假 | False or True,返回True |
not | not a | 输出结果与原式相反 | not True,返回False |
print(45>67 and 78<90)
print(56<=78 or 78-13>67+28)
print(not 89<90)
print(90 and 68)
? 注意: 1. 运算顺序:先算数运算,在比较运算,最后逻辑运算
? 2. 逻辑运算符优先级顺序:not
> and
> or
? 3. 表达式成立为真,不成立为假
? 表达式:由数值和运算符组成
? 4. 若两边为数字,则看运算符返回:(0 – False 和1 – True 特殊对待)
? e.g. and
返回第二个数字;or
返回第一个数字;not
返回False
,遇到0
返回True
? 5. True
和 False
是运算的结果,不是符号
? 顺序流程:无缩进代码,从上往下依次执行
? 分支流程:选择性执行某块代码,或跳过某行代码去执行,与缩进(TAB
)有关
? 循环流程:循环执行某块代码,最后回到终点
? 第一种分支结构:if
if结构的代码格式:
if 判断条件:
条件成立后执行的代码
? *注意:*1. 判断条件可以是一个数值,也可以是一个表达式
? 2. 如果判断条件是一个数值,只要不是0都是成立的 – 非0即真(True),为0为假(False)
? 3. 如果判断条件是一个序列;字符串,只要里面不是空的都是成立的 – 非空即真(True),为空为假(False),空格不算空,默认才为空,空格为真(True),会执行
? 4. 如果判断条件是一个表达式,则直接看表达式运算后的结果是否为真
? 5. if
是一定会执行的代码,而if里面的代码看是否满足判断条件,满足就执行,不满足则跳过
if 0:
print("不成立")
if 23:
print("成立")
if "":
print("不成立")
if [ ]:
print("成立")
if 0 and 89:
print("不成立")
if 0 or 89:
print("成立")
? 第二种分支结构:if - else
if - else
结构的代码格式:
if 判断条件:
条件成立后执行的代码
else:
条件不成立后执行的代码
? 注意: 1. if
可以单独出现,而else
不可以单独出现
? 2. if - else
是一块代码,不会发生先后一起执行的情况,而是看判断条件是否满足
if 23>67:
print("成立执行")
else:
print("不成立执行")
? 第三种分支结构:if - elif - else
if - elif - else
结构的代码格式:当判断条件为多个值时使用
if 判断条件1:
条件1成立后执行的代码
elif 判断条件2:
条件2成立后执行的代码
elif 判断条件3:
条件3成立后执行的代码
......
else:
当以上条件都不成立时执行的代码
? 注意: 分支结构可以没有 elif
和 else
,但一定要有 if
**`and`;`or`**
if 判断条件1 and 判断条件2:
两个条件都成立后执行的代码
elif 判断条件3 or 判断条件4:
只有一个或两个都成立后执行的代码
else:
当以上条件都不成立时执行的代码
nan = int(input("请输入男方的年龄:"))
nu = int(input("请输入女方的年龄:"))
if nan>22 and nu>20:
print("可以结婚")
else:
print("不可以结婚")
if
嵌套:
if
嵌套的代码格式:
if 条件判断1:
if 条件判断2:
当两个条件都成立时执行的代码
nan = int(input("请输入男方的年龄:"))
nu = int(input("请输入女方的年龄:"))
if nan>22:
if nu>20:
print("可以结婚")
else:
print("不可以结婚")
else:
print("不可以结婚")
? 三目运算符也叫三元运算符或三元表达式 – if - else
的简写
三目运算的代码格式:
? 先肯定再说条件最后说不满足条件时怎么办
变量名 = 条件成立后执行的代码 if 判断条件 else 条件不成立后执行的代码
print("变量名")
a = "可以请假" if int(input("请输入你的工资:"))>=10000000 else "不可以请假"
print(a)
while
循环while
循环:? 在Python编程中 while
语句用于循环执行程序,即在某一条件下,循环执行某段程序
while
循环语句的语法格式:
while 判断条件:
当条件成立时执行的语句
? 注意: 1. 判断条件可以是一个数值,也可以是一个表达式
? 2. 如果判断条件是一个数值,只要不是0都是成立的 – 非0即真(True),为0为假(False)
? 3. 如果判断条件是一个序列;字符串,只要里面不是空的都是成立的 – 非空即真(True),为空为假(False),空格不算空,默认才为空,空格为真(True),会执行
? 4. 如果在代码块中没有设置控制变量,那么当条件为真时,会出现死循环;当条件为假时,那么这一代码块,不会执行
? 5. 如果判断条件是一个表达式,则直接看表达式运算后的结果是否为真
#打印1~100
i = 0
a = 1
while a <= 100:
i = i + 1
a = a + 1
print(i)
控制语句 | 描述 |
---|---|
break 语句 | 用于终止循环,并跳出整个循环结构 |
continue 语句 | 用于终止当前循环,并跳出该次循环,执行下一次循环 |
pass 语句 | 空语句,用于保持程序结构的完整性,无意义 |
? 注意: 1. 在Python中,continue
和break
是两个控制流语句,用于在循环中进行不同的控制流操作
? 2. 当遇到continue
语句时,循环中剩余的代码将会被忽略,循环会立即进入下一次迭代
? 3. 当遇到break
语句时,整个循环立即结束。不再执行
#打印1~100,跳过偶数
i = 0
a = 1
while a <= 100:
i = i + 1
a = a + 1
if i % 2 == 0:
continue
print(i)
#在1~50中,当遇到7的倍数时跳出循环,不包含7,在让其余的数相加
i = 0
a = 1
b = 0
while a <= 50:
i = i + 1
a = a + 1
if i % 7 == 0 and i != 7:
break
b = b + i
print(b)
while
循环嵌套:? 当内部循环执行完成之后,再执行下一次外部循环的条件判断
#道歉三天,每一天说十次我错了
i = 1
while i < 6:
print(f"第{i}天道歉")
i = i + 1
a = 1
while a < 6:
print("对不起")
a += 1
#打印九九乘法表
i = 1
while i < 10:
o = 1
while o <= i:
print(f"{o}*{i}={i*o}", end="\t")
o += 1
print()
i += 1
for...in...
循环for...in...
循环可以遍历任何序列的项目,如一个列表或者一个字符串,只有序列才可以进行遍历for...in...
循环遍历的对象必须是可迭代对象,for…in…循环也可以理解为迭代循环while
循环的循环条件是自定义的,for...in...
循环无法定义循环条件for...in..
.循环是一种"轮循"机制,是对一批内容进行"逐个处理"
for...in...
循环的语法格式:
for 临时变量 in 可迭代对象(就是容器):
循环体
? 注意: 1. 迭代:取值的过程,从前往后,不插队,不重复,这样的过程叫做迭代
? 2. 取值:从可迭代对象中取值,赋值给临时变量,每一次循环都取一个值
? 3. 临时变量:只能在for...in...
循环中使用,每一次循环的值都不同,只能够保存当前循环的值,所以无法在for...in...
循环中被单独赋值
? 4. in指的是临时变量在可迭代对象的里面,每一次循环临时变量都是从可迭代对象中取值
a = [1,2,3,4,5]
for i in a:
print(i)
#计算1~5相加的数字之和
a = 0
for i in "12345":
a = a + int(i)
print(a)
? 注意: 凡是数字超过9的就不能使用字符串,因为无法用字符串存储,字符串里面都是单独的个体
range()
函数:? 作用:生成一个连续的数字序列
range()
函数的第一种用法:
range(num)
#num表示生成0~num-1的连续数字序列
? 注意: 1. range()
函数生成的类型是一个range
类型
? 2. 单独使用时要用序列(字典除外)对其进行转换,将其里面的连续数字序列显示出来
print(list(range(10)))#生成一个0~9的连续数字序列(列表)
print(set(range(10)))#生成一个0~9的连续数字序列(集合)
? 注意: 1. 因为集合是一个无序的序列,所以当把range
类型转换成集合时,打印时可能会打乱里面的数字顺序,但在python3.x的版本中,如果集合里面是纯数字,在一定的范围内,是不会出现乱序的,但如果里面是字符串,数字,变量等掺和在一起,就会出现乱序
? 2. 序列不可以转换成range()
? 3. range()
函数是生成一个可迭代的序列,而序列本身就是可迭代的
range()
函数的第二种用法:
range(n,m)
#n表示连续数字序列的起始值
#m表示m-1(因为不包含其m本身)是连续数字序列的结束值
print(tuple(range(3,16)))#生成一个3~15的连续数字序列(元组)
#计算1~100相加的数字之和
a = 0
for i in range(1,101):#当for...in...循环后面是可迭代对象时不用转换
a += i
print(a)
#计算1~100之间的偶数之和
a = 0
for s in range(1,101):
if s % 2 != 0:
continue
a += s
print(a)
range()
函数的第三种用法:
range(n,m,s)
#n表示连续数字序列的起始值
#m表示m-1(因为不包含其m本身)是连续数字序列的结束值
#s表示步长值(间隔值)起始值到结束值之间众多数字的差值
print(list(range(1,10,2)))#生成的数字就是[1,3,5,7,9],因为它们之间的差值为2
#计算1~100之间的偶数之和
a = 0
for s in range(0,101,2):
a += s
print(a)
? 当不需要用到临时变量时,可迭代对象就变成了循环次数,里面有几个元素,循环体就执行几次
a = 0
for i in ["112",a,18]:
print("对不起") #只会打印三次对不起
? 每一次的外部循环,内部都要重新开始再循环一遍
#道歉三天,每一天说十次我错了
for i in [1,2,3]:
print(f"第{i}天道歉")
for s in range(10):
print("我错了")
#打印九九乘法表
for i in range(1,10):
for s in range(1,1+i):
print(f"{s}*{i}={s*i}",end="\t")
print()
? 注意: else
不能够单独出现,但else
可以和if
使用,还可以与for
和while
循环一起同级使用,先执行循环里面的内容,待所有循环正常执行完毕后(被break
或其它原因中断,都属于非正常执行完毕),才会去执行else
里面的内容
#猜字游戏
import random
s = random.randint(1,100)
for i in "43210":
w = int(input("请输入数字:"))
if w == s:
print("恭喜你猜对了")
break
elif w > s:
print("猜大了")
print(f"回答错误,你还有{i}次机会")
elif w < s:
print("猜小了")
print(f"回答错误,你还有{i}次机会")
else:
print("抱歉,您的机会已经用完了!")
#道歉三天,每一天说十次我错了
i = 1
while i < 6:
print(f"第{i}天道歉")
i = i + 1
a = 1
while a < 6:
print("对不起")
a += 1
else:
print("我原谅你了!")
? 字符串是Python中最基本的数据类型之一,是可以存放多个单个单一元素的容器
? 字符串是Python中序列的一种,是一个有序不可变序列
? 由于字符串是不可变的序列,所以无法对其里面的内容进行修改,只能在去重新开辟空间存储
? Python会对容器中的元素进行编号,也就是下标(索引)
? 索引是指通过下标找到某一个元素
? 索引分为正向索引和负向索引:正向索引从左到右,以0为起始点;负向索引从右到左,以-1为起始点
用下标去获取元素,用索引符号 [] 去索引,对象/变量名[下标]
a = "longze"
#用负向索引获取元素e
print(a[-1])
#用正向索引获取元素n
print(a[2])
? 切片是指只截取一部分可操作的对象,字符串,列表,元组都支持切片操作
? 切片是指通过一段下标,找到某一段元素
? 凡需要获取的元素大于等于两位就都用切片
? 在切片中正向索引第三参数默认为1
(可以省略),负向索引第三参数为-1
(必须写)
用切片去获取某一段元素,用索引符号 [] 去索引,对象/变量名[起始下标:结束下标:正负向参数(步长)]
? 注意: 冒号 : 是一个范围符号,表示下标从某一个范围到某一个范围,冒号的左边是范围的起始,右边是指范围的结束**(结束下标不包含其本身,结束下标=结束下标-1)**
a = "longzeqiaoyue"
#用正整数正向索引获取g~y
print(a[3:11])
#用正整数负向索引获取y~g
print(a[10:2:-1])
#用负整数正向索引获取g~y
print(a[-10:-2])
#用负整数负向索引获取y~g
print(a[-3:-11:-1])
? 图示:
1
len()函数:获取对象中元素的长度
a = "longze0313jiang0327qiaoyue2023"
#获取a中所有元素的长度
print(len(a))
#获取所有元素
print(a[:])
print(a[0:len(a)])
#获取奇数位上的所有元素
print(a[0:len(a):2])
#获取偶数位上的所有元素
print(a[1:len(a):2])
? 字符串的常用操作方法有查找,修改和判断三大类
? 字符串方法的调用:对象/变量名.方法()
一:查找
? 字符串的查找方法即是查找子串在字符串中出现的位置或出现的次数
find()
方法:通过指定的元素(当有重复元素出现时,只能找到第一次出现的元素)去查询与之对应的下标 (索引)值(从左往右查询),当find()
方法查询到一个不存在的元素时,会返回一个数值-1
find()
方法的语法格式:对象/变量名.find(想要查询的元素字符,起始点(刚才查询到的下标+1),结束位置)
a = "longzeo"
#在此字符串中有两个o,但find()方法只能查询到从左往右第一次出现的o
print(a.find('o'))
#要想往右继续找重复出现的元素的下标(但也只找第一次出现的),可以在find()方法中设置起始参数和结束参数
print(a.find('o',2,len(a)))
print("longzeo".find('o',2,len("longzeo")))
rfind()方法:通过指定的元素(当有重复元素出现时,只能找到第一次出现的元素)去查询与之对应的下标 (索引)值(从右往左查询,但下标值是从左往右正向索引的下标值),当rfind()方法查询到一 个不存在的元素时,会返回一个数值-1
rfind()方法的语法格式:对象/变量名.rfind(想要查询的元素字符,结束位置,起始点(刚才查询到的下标-1))
a = "longzeo"
#在此字符串中有两个o,但rfind()方法只能查询到从右往左第一次出现的o
print(a.rfind('o'))
#要想往左继续找重复出现的元素的下标(但也只找第一次出现的),可以在rfind()方法中设置起始参数和结束参数
print(a.rfind('o',0,5)
print("longzeo".find('o',0,5)
index()方法:通过指定的元素去查询下标,从左往右去找,与find()方法类似,唯一不同的是,当index()方法 查询到一个不存在的元素时,会发生报错
rindex()方法:通过指定的元素去查询下标,从右往左去找,与rfind()方法类似,唯一不同的是,当index()方 法查询到一个不存在的元素时,会发生报错
count()方法:用于统计指定的某个字符出现的次数
count()方法的语法格式:对象/变量名.count(想要查询的元素字符,起始点,结束位置)
a = "sdfyuiolkjgxcvbnklkjgf"
print(a.count('g'))
print(a.count('g',0,21))
二:修改
? 对字符串中的内容进行修改
? 注意: 字符串本身是不可变类型,定义之后,无法被修改 ! ! !
replace()
方法:将指定的字符替换成新的字符
replace()
方法的语法格式:对象/变量名.replace(要被替换的字符,要替换成为的新字符,count = -1)? count = -1指定的是替换的次数,默认值为-1,也就是在不设置这个参数的时候,就相当于替换全部,当第三参数超出了可替换的范围的时候,也相当于替换全部,是无用的,但不会报错
a = "woaini"
print(a.replace('ni','ziji'))
c = "asdfghjkiii"
#只把两个i替换成o
print(c.replace('i','o',2))
? 注意: 1. a并没有真正意义上被替换,再次输出a时依旧是原字符串,replace()
只是作为临时修改
? 2. 要想使用被修改掉的临时字符串,只能重新的用变量去赋值
? 3. 只要对字符串进行重新赋值,就相当于系统为其又开辟了一个空间,不在是原字符串
a = "woaini"
b = a.replace('ni','ziji')
print(b)
split()方法:将字符串中的某个字符作为分割字符,将这个字符串分割成多个子字符串,最终的结果以列表的 形式输出,用作指定的分割字符会自动转变为列表里的分割字符,也就是逗号;若作为分割字符 的两个元素是挨着的,则都会变成空字符存储;当分割字符非字符串中的字符,则不发生 任何改变,自动将这个字符串转换为列表输出
split()方法的语法格式:对象/变量名.split(指定的字符串里的字符)
a = "qeqtqyquiqo"
print(a.split('q'))
print(a.split('+++'))
b = "67899"
print(b.split('9'))
a = input("请输入个人信息,并用空格分开:").split()
#因为split()里面没有加入分割字符,当输入的个人信息有空格时,split()会自动把空格当做分割字符
print(a)
join()方法:把字符串/字符序列中每个元素按照指定的符号进行连接
join()方法的语法格式:分割字符(这里可以是任何字符).join(字符串/字符序列)
a = "qwert"#这里的每个字符都是单独的个体
print('+'.join(a))
b = ["qwe","567",a]#这里的每个元素都是单独的个体
print('@'.join(b))
c = ''.join("wer")#因为是空分割符,所以正常输出
print(c)
d = {"hj":"qwe","tyuiol":"567"}#当是字典时只会拼接键
print('@'.join(d))
? 注意: 1. join()
方法通常被用于字符串的拼接,与字符串相加所实现的效果是一样的,但join()
方法会让拼接的效率更高
? 2. join()
方法不能拼接带数字的字符序列,只能是字符串
a = "tyu"+"hj"
print(a)
截取
lstrip()方法:去除字符串最左侧的空格
lstrip()方法的语法格式:对象/变量名.lstrip(chars)
chars参数默认情况下为None,也就是什么都没有,意思是去除的是空格,这个参数可以给它传入一个字符串对象中从最左侧开始连续的字符串,意思是把最左侧的什么什么给去除
a = " ai love you"
print(a.lstrip())
print(a.lstrip(" ai"))
rstrip()方法:去除字符串最右侧的空格
rstrip()方法的语法格式:对象/变量名.rstrip(chars)
? chars参数默认情况下为None,也就是什么都没有,意思是去除的是空格,这个参数可以给它传入一个字符串对象中从最右侧开始连续的字符串,意思是把最右侧的什么什么给去除
a = "ai love you "
print(a.rstrip())
print(a.rstrip("you "))
strip()方法:去除字符串左右侧的空格
strip()方法的语法格式:对象/变量名.strip(chars)
? chars参数默认情况下为None,也就是什么都没有,意思是去除的是空格,这个参数可以给它传入一个字符串对象中从最左侧或最右侧开始的字符串,意思是同时去除左侧和右侧相匹配的字符串
a = " ai love you "
print(a.strip())
print(a.strip(" au"))
removeprefix()方法:允许指定将要删除的字符串前缀
removeprefix()方法的语法格式:对象/变量名.removeprefix(连续的字符串前缀)
a = "asdff mmm iofewp"
print(a.removeprefix("asd"))
removesuffix()方法:允许指定将要删除的字符串后缀
removesuffix()方法的语法格式:对象/变量名.removesuffix(连续的字符串后缀)
a = "asdff mmm iofewp"
print(a.removesuffix("wp"))
左中右对齐
ljust()方法:左对齐(填充右侧),并使用指定字符(默认空格)填充至对应长度的空字符串
ljust()方法的语法格式:对象/变量名.ljust(指定整个字符串的长度,指定字符填充对应长度(默认空格))
a = "我爱你"
print(a.ljust(8,'$'))
rjust()方法:右对齐(填充左侧),并使用指定字符(默认空格)填充至对应长度的空字符串
rjust()方法的语法格式:对象/变量名.rjust(指定整个字符串的长度,指定字符填充对应长度(默认空格))
a = "我爱你"
print(a.rjust(8,'$'))
center()方法:字符串居中(填充左右两侧),并使用指定字符(默认空格)填充至对应长度的空字符串
center()方法的语法格式:对象/变量名.center(指定整个字符串的长度,指定字符填充对应长度(默认空格))
a = "我爱你"
print(a.center(8,'$'))
zfill()方法:用0去填充左侧
zfill()方法的语法格式:对象/变量名.zfill(指定整个字符串的长度)
a = "我爱你"
print(a.zfill(8))
? 注意: 1. zfill()
方法在做数据报表的时候会比较实用
? 2. zfill()
方法也可以处理带负数的情况,它并不是一味的在左侧填充0,它会把负号挪到最左面去,当然负号也占一个字符
a = "-520"
print(a.zfill(5))
大小写转换
capitalize()方法:将字符串中的第一个字母变成大写
a = "aasdef qwer"
print(a.capitalize())
casefold()方法:返回一个所有字母都是小写的新字符串
a = "ASDFGH"
print(a.casefold())
title()方法:将字符串中的每个单词的首字母都变成大写,其余所有字母都变成小写
a = "SDF JKL asdf"
print(a.title())
upper()方法:将字符串中的所有字母都变成大写
a = "asdf jklo ASio"
print(a.upper())
lower()方法:将字符串中的所有字母都变成小写
a = "DFGHJ asKO"
print(a.lower())
swapcase()方法:将字符串中的所有字母大小写翻转,大写变小写,小写变大写
a = "ASDF Hijw"
print(a.swapcase())
? 注意: 空格之后的每一个单词都表示一个新的单词
三:判断
? 判断方法的结果都是布尔值:正确返回True,错误返回False
startswith()方法:判断字符串是否以指定的子字符串为开头
startswith()方法的语法格式:对象/变量名.startswith(指定的子字符串,起始点下标,结束下标)
? 也可指定一个范围去查找这个范围的起始字符
a = "我爱你一生一世"
print(a.startswith("我爱"))
print(a.startswith("我",1,5))
endswith()方法:判断字符串是否以指定的子字符串为结尾
endswith()方法的语法格式:对象/变量名.endswith(指定的子字符串,起始点下标,结束下标)
? 也可指定一个范围去查找这个范围的结尾字符
a = "我爱你一生一世"
print(a.endswith("世"))
print(a.endswith("一世",3,6))
istitle()方法:判断一个字符串中所有单词是否都是以大写字母开头,其余字母都是小写
istitle()方法的语法格式:对象/变量名.istitle()
a = "lOve YOU"
print(a.istitle())
isupper()方法:判断一个字符串中是否所有字母都是大写字母
isupper()方法的语法格式:对象/变量名.isupper()
a = "lOve YOU"
print(a.isupper())
islower()方法:判断一个字符串中是否所有字母都是小写字母
islower()方法的语法格式:对象/变量名.islower()
a = "love you"
print(a.islower())
isalpha()方法:判断一个字符串中是否只有字母构成(中间有空格也算False)
isalpha()方法的语法格式:对象/变量名.isalpha()
a = "loveyou"
print(a.isalpha())
isspace()方法:判断是否为一个空白字符串(并不是只有空格才算空白字符串,例如:tab,转义字符\n也都 是空白字符串
isspace()方法的语法格式:对象/变量名.isspace()
print("\n".isspace())
isprintable()方法:判断一个字符串中是否所有字符都是可打印的,例如:转义字符\n并不是一个可打印字符
isprintable()方法的语法格式:对象/变量名.isprintable()
a = "fwcww\n"
print(a.isprintable())
isdigit()方法:可以用来判断一个字符串中是否是纯数字,只可用来判断单一的数字
isdigit()方法的语法格式:对象/变量名.isdigit()
a = "12345"
print(a.isdigit())
isalnum()方法:判断一个字符串中是否是字母或数字
isalnum()方法的语法格式:对象/变量名.isalnum()
a = "123asd45"
print(a.isalnum())
符号 | 描述 |
---|---|
+ | 字符串的拼接 |
[] | 通过索引获取到字符串中的字符 |
[:] | 切片,获取到一段字符串 |
in | 成员运算符 – 如果字符串中包含给定的字符返回True |
not in | 成员运算符 – 如果字符串中不包含给定的字符返回True |
r | 取消转义 |
% | 格式化字符串 |
#给定的字符 in 字符串(对象)/变量名
a = "qwert"
print('t' in a)
#给定的字符 not in 字符串(对象)/变量名
print('q' not in "rtyuigh")
#取消转义
print(r"hello\nya")
? 列表是Python中最基本的数据类型之一,是可以存放多个多种元素的容器
? 列表是Python中序列的一种,是一个有序可变序列
? 由于列表是可变序列,所以可以对其里面的内容进行修改,无需重新开辟空间存储
? 列表中也可以应用下标索引和切片,与在字符串中的应用一样
创建列表:使用中括号 [] 将所有准备放入列表中的元素给包裹起来,不同元素之间使用英文逗号隔开
? 列表中可以放入整型,浮点型,字符串和变量名等
v = "123"
a = ["我",520,1.86,v,1,2,3]
#用正数正向索引打印1.86
print(a[2])
#用负数负向索引打印520
print(a[-6])
#用正向切片获取520~2
print(a[1:6])
print(a[-6:-1])
#用负向切片获取2~520
print(a[5:0:-1])
print(a[-2:-7:-1])
? 列表的常用操作方法有增加,删除,修改,查找
? 列表方法的调用:对象/变量名.方法()
一:增加
? 向列表中添加指定的元素
append()方法:在列表的末尾添加一个指定的元素,且每次只能添加一个元素
? append()方法是对列表进行修改,其本身是没有返回值的,不能够直接输出
append()方法的语法格式:列表对象/变量名.append(元素)
a = [123,456]
a.append(789)
print(a)
extend()方法:在末尾添加一个序列,extend()方法的参数必须是一个序列,其本身没有返回值
? 新添加的内容是将序列中的每一个元素都追加到原列表最后一个元素的后面
? 只能添加一个参数,但可以将多个参数存储在序列这一个参数里面
extend()方法的语法格式:列表对象/变量名.extend(序列)
a = [1,5,3,8,0]
a.extend(["122","你好",11])
print(a)
insert()方法:在指定的任意位置添加一个元素,insert()方法不是替换,而是让待插入位置上的元素整体后退
insert()方法的语法格式:列表对象/变量名.insert(指定待插入的下标位置,指定待插入的元素)
a = ["我","上","你"]
a.insert(1,"爱")
print(a)
二:删除
? 删除列表中的元素
pop()方法:删除指定下标位置上的元素
pop()方法的语法格式:列表对象/变量名.pop(要删除的那个元素的下标索引)
a = [1,2,3,4,5,3]
a.pop(3)
print(a)
remove()方法:删除指定的元素
? 如果列表中存在多个相匹配的元素,那么它只会删除第一个找到的元素
? 如果指定的那个元素不存在,那么程序会发生报错
remove()方法的语法格式:列表对象/变量名.remove(要删除的元素)
a = ["我","爱","12","你"]
a.remove("12")
print(a)
del销毁语句:销毁掉这个列表或者其元素,释放内存空间
del的语法格式:del 列表名[要删除的某一元素的下标索引]
? del 列表名
a = [1,2,3,4,5]
del a[2]
print(a)
del a
print(a)
? 注意: 当del
已经将这个列表销毁时,再次访问输出会发生报错
clear()方法:清空列表中的所有元素,只留下空列表
clear()方法的语法格式:列表对象/变量名.clear()
a = [1,3,4,5,7,9]
a.clear()
print(a)
三:修改
? 先找到这个元素,然后对它进行重新赋值
根据下标直接修改:
? 替换单个元素的语法格式:列表名[要被替换的元素的下标索引] = 替换的元素
? 替换多个元素的语法格式:列表名[起始下标:结束下标:步长] = 替换的元素
a = [1,2,3,4,5,6,7]
a[2] = "我"
print(a)
a[0:5:2] = ["爱","love",0]
print(a)
当不知道某个元素的索引值,想将其替换成新的元素时:
? 列表名[列表名.index(被替换的元素)] = 替换的元素
a = [1,2,3,4,5,6]
a[a.index(3)] = "ai"
print(a)
reverse()方法:逆置,将列表中的元素翻转
reverse()方法的语法格式:列表名.reverse()
a = ["a",3,"yu",9,7,"se"]
a.reverse()
print(a)
sort()方法:只用于数字序列,对数字进行从小到大的排序
sort()方法的语法格式:列表名.sort()
a = [1,5,4,7,9,10,45,94,14]
a.sort()
print(a)
? 注意: reverse()
的默认值为False,如果将它设置为True,那么排序的结果就会原地翻转
#直接实现数字从大到小排序
列表名.sort(reverse = True)
a = [1,3,23,65,34,78,10]
a.sort(reverse = True)
copy()方法:对一维列表进行拷贝
copy()方法的语法格式:列表对象/变量名.copy()
a = [1,3,5,7,9]
b = a.copy()
print(b)
四:查找
index()方法:通过指定的元素去查询下标,只找从左到右第一个找到的下标,当index()方法查询到一个不存 在的元素时,会发生报错
index()方法地1语法格式:对象/变量名.index(要查询的元素字符,起始点(刚才查询到的下标+1),结束位置)
a = [1,2,3,4,5,4]
print(a.index(4))
print(a.index(4,2,4))
count()方法:用于统计指定的某个字符出现的次数
count()方法的语法格式:列表对象/变量名.count(要查询的元素)
a = [1,4,2,4,2,5,6,4]
print(a.count(4))
len()函数:查询列表中的元素长度
a = [1,5,4,87,34]
print(len(a))
? 只应用于序列类型当中
符号 | 作用 |
---|---|
in | 左边是否在右边里 |
not in | 左边是否不在右边里 |
a = [1,2,3,5,7,0]
print(3 in a)
print(8 not in a)
? 注意: 1. 成员判断符只能判断一维列表的成员关系
? 2. 若要判断嵌套列表里一维列表的元素,则应该先把它索引出来
a = [1,["long"],"泽"]
print("long" in a[1])
列表的加法与乘法:
? 列表的加法就是拼接,加号两边必须都是列表
a = ["我","爱","你"]
b = ["才","怪"]
print(a + b)
? 列表的乘法则是重复列表内的所有元素若干次
a = [1,2,3]
print(a * 3)
嵌套列表(二维列表):
? 所谓的列表嵌套就是在列表里面嵌套一个新的列表
a = [[1,2,3],["才","怪"],[4,5,6]]
访问嵌套列表:
? 1. 访问嵌套列表中的元素可以用循环来实现,迭代一个列表,嵌套一层循环,迭代嵌套列表,则对应的使用嵌套列表,依此类推
a = [[1,2,3],[4,5,6],[7,8,9]]
for i in a:
for w in i:
print(w)
? 2. 通过下标索引来访问嵌套列表
a = [[1,2,3],
[4,5,6],
[7,8,9]]
print(a[1])
? 如果只给出一个下标索引的话,得到的是以行为单位的整个列表,而非嵌套列表中的列表
? 为了访问嵌套列表中的列表的元素,需要使用两次的下标索引
? 第一个下标索引指的是整个列表中的 “行”
? 第二个下标索引指的是这一行里面对应的 “列”
a = [[1,2,3],
[4,5,6],
[7,8,9]]
#访问第二行第三列的元素
print(a[1][2])
通过循环创建并初始化二维列表:
a = [] # 创建一个空列表
for i in range(3): # 循环3次
b = [] # 创建一个空列表作为当前行的元素
for j in range(3): # 循环3次
b.append(0) # 将0添加到当前行列表中
a.append(b) # 将当前行列表添加到二维列表中
print(a) # 输出二维列表
# 错误示范 -- 容易导致出现BUG
b = [[0] * 3] * 3
print(b)
符号 | 作用 |
---|---|
is | 用于检验两个变量是否指向同一对象 |
a = "wo"
b = "wo"
print(a is b) #True
a = [1,2,3]
b = [1,2,3]
print(a is b) #False
? 以上说明了在Python中,对于不同对象的存储机制是不一样的
? 如:字符串是不可变的,当有多个变量名指向同一个字符串的情况时,它只需要在内存中开辟一个空间来存放就可以了
? 相比字符串,列表是可变的,列表内的元素可以添加或删除,尽管两个列表的内容一致,但Python还是要为它们开辟两个不同的空间位置进行存放
? 通过以上结论:检测二维列表a和b:
a = []
for i in range(3):
b = []
for j in range(3):
b.append(0)
a.append(b)
print(a)
print(a[0] is a[1]) #False
? 结果是False,说明了不是同一对象,便不放在同一内存地址里面
# 错误示范 -- 容易导致出现BUG
b = [[0] * 3] * 3
print(b)
print(b[0] is b[1]) #True
? 结果是True,说明了是同一对象,且放在同一内存地址里面
? 经过以上实验论证,得知b的问题在于:
? 试图通过乘号对一个嵌套列表进行拷贝,但其实它只是对同一个列表进行重复的引用
引用:
? 变量就是一个名字,一个标签,通过这个变量,就可以找到对应的数据,在Python中。变量不是一个盒子,因为当赋值运算发生的时候,Python并不是将数据放到变量里面去,而是将变量与数据进行挂钩,这个行为,我们称之为引用
? 将一个变量赋值给另一个变量,其实就是将一个变量引用传递给另一个变量
? 如果想要得到两个独立的列表,就要用到拷贝,拷贝之后的列表是独立的,而引用后的列表会随着远列表的改变而改变,一维列表用浅拷贝,多维列表用深拷贝
一:浅拷贝:
? 调用列表的copy()方法,copy()
方法拷贝的是整个的列表对象,不仅仅是变量的引用
? 使用切片也可以实现浅拷贝
? 注意: 用浅拷贝处理一维列表是没有问题的,但如果是嵌套列表,对拷贝的那个列表是有干扰的,因为嵌套列表只是拷贝了外层的对象,如果包含嵌套对象的话,那么拷贝的只是其引用,要解决这个问题,就要用到深拷贝
二:深拷贝:
? 调用copy模块
? copy()
模块中有两个函数
(1)一个是copy()
:实现的是浅拷贝
copy()的语法格式:
? 导入函数:import copy
? 使用函数:要接收拷贝的变量名 = copy.copy(提供列表的变量名)
import copy
a = [1,2,3,4,5,6,7,8,9]
b = copy.copy(a)
print(b)
(2)另一个是deepcopy()
:实现的是深拷贝
deepcopy()的语法格式:
? 导入函数:import copy
? 使用函数:要接收拷贝的变量名 = copy.deepcopy(提供列表的变量名)
import copy
a = [[1,2,3],[4,5,6],[7,8,9]]
b = copy.deepcopy(a)
print(b)
? 深拷贝在原嵌套列表改变的同时,拷贝的列表也不会发生变化,因为deepcopy()
函数在将原对象拷贝的同时,也将对象中所有的子对象一并进行了拷贝。如果存在多层嵌套的情况下,深拷贝也会拷贝每一层嵌套里的数据
? 注意: copy.copy()
指的是copy
模块中一个叫copy()
的函数;变量名.copy()
指的是列表的一个copy()
方法,但它们所实现的都是浅拷贝
? 列表推导式的构建:
基本语法一:
[表达式 for 变量 in 可迭代对象]
? 注意: 1. 列表推导式一定要是一个列表,所以列表推导式要用 [] 包裹
? 2. 由于列表推导式的结果是使用一组数据来填充这个列表的,所以需要一个for
语句来搭配,最后在for
语句的左侧放一个表达式,相当于循环体,经过运算才决定存放在列表中的数据
? 3. 表达式是列表中的元素,它一定要是for循环中产生的值,不能是不被定义的,要与临时变量保持一致
a = [b for b in range(10)]
print(a) #最后的结果由i决定
a = [b + 1 for b in range(10)]
print(a) #列表中的每一个元素都加1
a = [b * 2 for b in "long"]
print(a) #将字符串中的每个元素重复两遍,并存储在列表中
ord()函数:将单个字符转换为对应的Unicode编码,并保存在列表
a = [ord(b) for b in "long"]
print(a)
通过列表推导式将嵌套列表中的元素提取出来:
a = [[1,2,3],
[4,5,6],
[7,8,9]]
b = [i[1] for i in a] #将每一行的第二个元素提取
print(b)
通过列表推导式将嵌套列表中对角线的元素提取出来:
a = [[1,2,3],
[4,5,6],
[7,8,9]]
b = [a[t][t] for t in range(len(a))] #获取从左上角到右上角上的元素
print(b)
? 注意: 循环是通过迭代来逐个修改原列表中的元素。而列表推导式则是直接创建一个新的列表,然后再拷贝给原先的列表名
基本语法二:
[表达式 for 变量 in 可迭代对象 if 条件判断]
? 注意: 执行顺序是先执行for
语句,在执行if
语句,最后在执行左侧的表达式
#求偶数
a = [i for i in range(10) if i % 2 == 0]
print(a)
#求奇数
a = [i + 1 for i in range(10) if i % 2 == 0]
print(a)
#筛选出开头为f的单词
a = ["for","great","from","apple"]
b = [i for i in a if i[0] == 'f']
print(b)
列表推导式的嵌套语法:
[表达式 for 变量 in 可迭代对象1
? for 变量 in 可迭代对象2
? …
? for 变量 in 可迭代对象n]
? 注意: 1.嵌套的列表推导式对应嵌套循环
? 2. 外层循环是放在前面的,嵌套的循环是放在后面的,先执行前面的循环
#将二维列表将为一维列表
a = [[1,2,3],[4,5,6],[7,8,9]]
b = [z for i in a for z in i]
print(b)
#将二维列表将为一维列表
a = [[1,2,3],[4,5,6],[7,8,9]]
b = []
for i in a:
for z in i:
b.append(z)
print(b)
列表推导式的终极语法:
[表达式 for 变量 in 可迭代对象1 if 条件判断1
? for 变量 in 可迭代对象2 if 条件判断2
? …
? for 变量 in 可迭代对象n if 条件判断n]
? 注意: 每个for
语句的后面都可以追加一个if语句,用于进行条件筛选
a = [[1,2,3],[4,5,6],[7,8,9]]
b = [z+1 for i in a if i[1] > 1 for z in i if z % 2 == 0]
print(b)
? 1. 比较大小:
? 当有多个元素时,默认从第0索引元素开始比较。只要一个大,那整个列表就是大,不用进行后面的比较
a = [1,2,3]
b = [4,5,6]
print(a > b) #返回False
? 2. 拼接操作符:+
? 当要进行拼接的操作时,加号两边的对象类型必须保持一致,左边是列表,右边必须也得是列表
? 列表的拼接和字符串的拼接具有相似性,但并非完全一样,列表的拼接相当于使用extend()
的方法,使用extend()
方法来扩展列表会显得更加规范,随意使用加号去扩展列表的话,有一些操作是违规的
a = [1,2,3]
b = ["wo","ai"]
c = b + a
print(c)
a = (3,)
print(type(a))
b = ("嘟嘟",)
print(type(b))
访问一个元组的元素与访问一个列表的元素的方法是一样的,都是用下标索引
元组也可以进行切片操作,因为切片的含义是将目标对象中的元素以某种特定的组合导出一个新的对象,而并非修改对象本身
元组只支持index()方法,count()方法和len()函数,与列表的使用效果一样
元组也可以进行嵌套,对于嵌套的元组也同样要使用嵌套的循环
可以利用列表推导式,对原组进行一个转换
a = (1,2,3,4,5)
c = [b * 2 for b in a]
print(c)
? 原理:将a这个元组里边的每个元素都拿出来乘以2,然后把最终的结果生成一个列表
? 注意: 1. 元组是不可变的,所以试图修改元组的内容,会出现报错
? 2. 英文逗号是构成元组的基本条件,对于元组来说逗号才是关键,圆括号并不是关键,逗号隔开的一组集合的数据,那么它默认就是创建了一个元组
? 3. 列表推导式不可将中括号改为原括号,这个写法生成的不是元组推导式,也没有元组推导式这种东西,生成的是生成器
? 4. 最好输写元组时一直都加上圆括号,不然容易产生错误,且这样做有助于代码的可读性
? 5. 当定义好的数据不希望被别人修改时,就使用元组存储
? 生成一个元组,也叫做元组的打包,那么对应的,将它们一次性赋值给多个变量的行为,称之为解包
a = (1,"wo",0)
x,y,z = a
print(x)
print(y)
print(z)
? 注意: 这种行为不仅适用于元组,也适用于任何的序列类型
#如:列表
a = [1,"wo",0]
x,y,z = a
print(x)
print(y)
print(z)
#如:字符串
a = "1","wo","0"
x,y,z = a
print(x)
print(y)
print(z)
? 注意: 无论使用哪一种序列的解包,都要注意赋值号左面的变量名的数量必须与右边序列的元素数量保持一致,否则,就会发生报错
a,b = 10,20
print(a)
print(b)
? 它背后的实现逻辑就是先通过元组进行打包,然后再将元组进行解包
? 注意: 元组也并非固若金汤,元组中的元素虽然是不可变的,但如果元组中的元素是指向一个可变的列表的时候,我们是可以修改列表里面的内容的
a = [1,2,3]
b = ["wo","ai"]
c = (a,b) #用一个元组将这两个列表放进去,此时,这个元组是可以被修改的
c[0][0] = 7 #访问c元组中的第一个元素,也就是a列表,访问a列表中的第一个元素,也就是1,将其修改为7
print(c)
set(
)表示,{}
表示的是空字典a = {1,45,3,4,56,6}
print(a) #输出的结果顺序是随机被打乱的
a = set()
print(a) #空集合
? 集合的常用操作方法有增加,删除和查询
一:增加
add()方法:在集合的随机位置添加一个元素
add()方法的语法格式:集合对象/变量名.add(要添加的元素)
a = {34,31,68,90,46}
a.add(77)
print(a)
? 注意: 1. 当添加的元素是原集合中已有的元素时,集合不会发生任何的改变
? 2. 集合会默认去重,将重复的元素给自动去除掉,不做存储
? 3. add()
方法一次只能添加一个元素,不然会报错
update()方法:将序列里的元素随机存储在集合中
update()方法的语法格式:集合对象/变量名.update(要添加的序列)
a = {"wo","ai",26,52,0}
a.update((46,"ui")) #存储了元组里面的元素
print(a)
a.update([46,"ui"]) #存储了列表里面的元素
print(a)
a.update([66,[46],"ui"]) #当要存储的元素有列表时,会发生报错
print(a)
a.update((46,(520,),"ui")) #存储了元组里面的元素,包含元组这个元素
print(a)
? 注意: 1. update()
方法只能是添加一个序列类型,若是添加其它的类型,会发生报错
? 2. 集合里只能存储不可变的类型,如:元组就可以存储,而列表就不能存储 – 可以存储列表里面的元素,但不能存储列表这个元素
二:删除
pop()方法:随机删除最后一个元素
pop()方法的语法格式:集合对象/变量名.pop()
a = {"wo",42,68,19,"ui"}
a.pop()
print(a)
? 注意: 因为集合元素的位置不确定,所以不知道删除的是哪个元素
remove()方法:删除指定的元素
remove()方法的语法格式:集合对象/变量名.remove(要删除的元素)
a = {"wo",42,68,19,"ui"}
a.remove(42)
print(a)
? 注意: 如果remove()
方法指定的那个元素不存在,那么程序会发生报错
discard()方法:删除指定的元素
discard()方法的语法格式:集合对象/变量名.discard(要删除的元素)
a = {"wo",42,68,19,"ui"}
a.discard(42)
print(a)
? 注意: discard()
方法与remove()
方法的区别在于,当discard()
方法指定的那个元素不存在时,程序不会发生报错,也不会做出任何改变,只会按原集合原样输出
del销毁语句:销毁掉这个集合,释放内存空间
del语句的语法格式:del 集合对象/变量名
a = {"wo",42,68,19,"ui"}
del a
print(a)
? 注意: 当del
已经将这个集合销毁时,再次访问输出会发生报错
clear()方法:清空集合中的所有元素,只留下空集合
clear()方法的语法格式:集合对象/变量名.clear()
a = {"wo",52,11,"ai",4.63}
a.clear()
print(a)
三:查询
len()函数:查询集合中的元素长度
a = {"wo",52,"99",("123,"),0}
print(len(a))
创建字典:
a = {键:值,键:值......} #键只能是不可变类型;值可以是任何的类型
创建空字典的两种方式:
a = {}
a = dict()
用一个键去存储多个值:
a = {"数字":(1,2,3,"无穷")}
print(a["数字"]) #会返回这个键所对应的所有的值
? 像其它的序列都是直接存储在内存中,Python会给它们分配一个编号。但在字典中只有键是直接存储在内存中,而值是储存在键中的。所以字典是没有下标的,都是通过键去索引从而进行操作的
通过索引实现查找/修改/增加:变量名[键] / 变量名[键] = 值 / 变量名[键] = 值
#查找值
a = {"嘟嘟":520,"咕咕":1314}
print(a["咕咕"])
#修改值
a["咕咕"] = 12345
print(a)
#增加新的键值对
a["嘻嘻"] = 100
print(a)
? 注意: (1)当用键去索引时如果这个键存在则返回其对应的值
? (2)当用键去索引时如果这个键存在并把这个键赋予新的值时,则会修改原本的值
? (3)当用键去索引时如果这个键不存在并将其赋予值时,则会在末尾添加这个新的键值对
? 字典的常用操作方法有增加,删除,修改,查找
一:增加
? 通过键的索引去添加
? 字典中新增加的键值对无法增加到指定的位置,都新加到最后一位
update()方法:将序列中的元素存储在字典中,一次可新建多个键值对
update()方法的语法格式:字典对象/变量名.update({键:值})
? 注意: update()
方法的参数是一个序列,不要忘记代表字典的大括号!!!
a = {"嘟嘟":520}
a.update({"咕咕":1314,"呼呼":"eee"})
print(a)
setdefault()方法:在字典的末尾增加一个键值对
setdefault()方法的语法格式:字典对象/变量名.setdefault(键,值)
a = {"嘟嘟":520,"咕咕":1314}
a.setdefault(520,1314)
print(a)
? 注意: (1)当setdefault()
括号中的键不存在时,则在末尾新增一个默认值为None
的键值对,也可以在setdefault()
的第二个参数中添加想要添加的值。如果setdefault()
括号中的键存在,那么无论是否添加值,都不会做任何的修改,因为setdefault()
方法没有修改的作用
? (2)setdefault()
方法一次只能添加一个键值对
二:删除
? 通过键的索引去删除
del销毁语句:销毁掉指定的这个字典或者其元素,释放内存空间
del的语法格式:del 字典名[要删除的键值对中的键]
? del 字典名
a = {"嘟嘟":520,"咕咕":1314}
del a["咕咕"] #销毁掉咕咕这个键值对
print(a)
del a #销毁a这个字典
pop()方法:通过指定键值对中的键去删除这个键值对
pop()方法的语法格式:字典对象/变量名.pop(要删除的键值对中的键)
a = {"嘟嘟":520,"咕咕":1314}
a.pop("咕咕")
print(a)
popitem()方法:默认删除字典当中最后的一个键值对,无法指定删除哪一个
popitem()方法的语法格式:字典对象/变量名.popitem()
a = {"嘟嘟":520,"咕咕":1314}
a.popitem()
print(a)
clear()方法:清空字典中的所有元素,只留下空字典
clear()方法的语法格式:字典对象/变量名.clear()
a = {"嘟嘟":520,"咕咕":1314}
a.clear()
print(a)
三:修改
? 字典中的值可以重复,但字典中的键是不允许重复的,重复的话字典会取第一个定义的键,和将前面的值覆盖掉的最后定义的值
update()方法:将字典中键所对应的值修改
update()方法的语法格式:字典对象/变量名.update({键:值})
a = {"嘟嘟":520,"咕咕":1314}
a.update({"咕咕":"呃呃呃"})
print(a)
? 注意: 如果这个键存在字典当中,那么update()
方法的作用就是修改,如果这个键不存在,那么update()方
法的作用就是在末尾增加一个键值对
四:查找
setdefault()方法:通过键查看这个键值对中的值
setdefault()方法的语法格式:字典对象/变量名.setdefault(键)
a = {"嘟嘟":520,"咕咕":1314}
a.setdefault("咕咕")
print(a)
? 注意: 如果这个键存在字典当中,那么setdefault()
方法的作用就是查看这个键值对中的值,如果这个键不存在,那么setdefault()
方法的作用就是默认在末尾增加一个值为None
的键值对
get()方法:通过键查看这个键值对中的值
get()方法的语法格式:字典对象/变量名.get(键)
a = {"嘟嘟":520,"咕咕":1314}
a.get("咕咕")
print(a)
? 注意: 如果这个键存在字典当中,那么get()
方法的作用就是查看这个键值对中的值,如果这个键不存在,那么get()
方法会返回None
? get()
方法与setdefault()
方法的区别就是当查看的键不存在时,setdefault()
方法会在键值对的末尾增加一个新的键值对,而get()
不会
for 临时变量 in 字典名:
只遍历键:因为值是存储在键里的,所以当遍历字典的时候就只遍历了键
keys()方法:查看字典里所有键值对中的键
a = {"嘟嘟":520,"咕咕":1314,"呃呃":456,"切切":789}
for i in a:
print(i)
#用keys()方法遍历键
a = {"嘟嘟":520,"咕咕":1314,"呃呃":456,"切切":789}
for i in a.keys():
print(i)
只遍历值:
values()方法:查看字典里所有键值对中的值
a = {"嘟嘟":520,"咕咕":1314,"呃呃":456,"切切":789}
for i in a.values():
print(i)
把一个键值对当成一个元素去遍历,查看所有的键值对
items()方法:返回一个元组
#去掉元组的两种方法:
#1.以两个变量去获取迭代的元组中的元素,第一个变量拿到第一个值,第二个变量拿到第二个值,以此类推
a = {"嘟嘟":520,"咕咕":1314,"呃呃":456,"切切":789}
for i,w in a.items():
print(i,w)
#2.用下标索引去输出
a = {"嘟嘟":520,"咕咕":1314,"呃呃":456,"切切":789}
for i in a.items():
print(i[0],i[1])
#直接以元组的形式输出
a = {"嘟嘟":520,"咕咕":1314,"呃呃":456,"切切":789}
for i in a.items():
print(i)
{键:值 for 临时变量 in 字典.items() if 条件判断}
#通过字典推导式快速的生成一个字典
a = {i:w for i,w in enumerate("hello",111)}
print(a)
b = {i:w for i,w in enumerate("hello",111) if i % 2 == 0}
print(b)
#将两个列表变成一个字典
a = ["name","age","sex"]
b = ["xxx",19,y]
c = {a[i]:b[i] for i in range(len(a))}
print(c)
#提取字典中大于200的目标数据
a = {"ccc":111,"bbb":890,"ddd",905,"eee":130}
m = {i:w for i,w in a.items() if w > 200}
print(a)
运算符 | 描述 | 支持的序列 |
---|---|---|
+ | 元素的合并拼接 | 字符串,列表,元组 |
* | 元素的复制重复 | 字符串,列表,元组 |
in | 是否存在 | 字符串,列表,元组,字典,集合 |
not in | 是否不存在 | 字符串,列表,元组,字典,集合 |
函数 | 描述 |
---|---|
len() | 统计序列中元素的个数 |
del 或 del() | 销毁语句 |
max() | 返回容器中元素最大值,不同类型之间不能进行比较 |
min() | 返回容器中元素最小值,不同类型之间不能进行比较 |
range(x,y,z) | 生成从x到y且不包括y的数字,步长为z |
enumerate(x,y) | enumerate(x,y)是一个迭代器,不能直接去查看里面的数据。用于将一个可遍历的数据对象(如:列表,元组,字符串)组合为一个索引序列,同时以元组的形式返回该序列的元素和与其对应的下标,一般用在for循环中。x是序列,而y是指定的下标从哪里开始,不设置时默认为0。enumerate(x,y)方法生成的是一个下标在前,元素在后的元组!!! |
sum() | 序列求和 |
zip() | 合并序列 |
#len()
print(len("12345"))
print(len(["12345",666]))
print(len(("12345",555)))
print(len({1,2,3}))
print(len({"1":2,"3":4}))
#max()和min()
print(max([1,3,6,7,23,12]))
print(max("14","65","90","33"))
print(min((132,43,68,95,34)))
#max()和min()也可以同时判断多个
#当有多个同一类型的序列时,默认两个序列从第0索引元素开始比较。只要一个大,那整个序列就是大,不用进行后面的比较
print(max([1,3,6,7,23,12],[12,32,56]))
print(min({132,43,68,95,34},{55,57,87,10}))
#enumerate()
for i in enumerate("helloworld"):
print(i) #返回的是以元组的形式输出的
#去除元组输出
for i,w in enumerate("helloworld"):
print(i,w)
#将helloworld以字典的形式存储的三种方法:
#第一种,索引赋值法
a = {}
for i,w in enumerate("helloworld",111):
a[w] = i #因为enumerate(x,y)方法生成的是一个下标在前,元素在后的元组,所以是w = i,键 = 值
print(a)
#第二种,update()方法
a = {}
for i,w in enumerate("helloworld",0):
a.update({w:i})
print(a)
#第三种,setdefault()方法
a = {}
for i,w in enumerate("helloworld",6):
a.setdefault(w,i)
print(a)
#虽然enumerate()不能直接打印输出,但却可以把它转换成其它的类型去输出查看里面的数据
print(list(enumerate("helloworld")))
? 函数:就是可以重复使用的具有一定功能的代码。除了一些Python内置的函数以外,函数也可以自己定义
? 自定义函数:通过 def 定义的函数
自定义函数格式:
def 函数名(参数):
函数要去实现的功能代码
#调用函数
函数名(参数)
#定义函数
def qiao():
print("函数,你好!")
#调用函数
qiao() #这里会自动执行其函数内部的功能代码
? 注意: 调用函数一定要在将这个函数定义完之后,先定义后使用
? 变量保存的是一段数据,而函数保存的则是一段代码
? 方法是用在类里面的,而函数则是用在程序里面的
? 参数是函数中一个重要的组成部分,一个没有参数的函数会显得不是那么的灵活;相反,一个有参数的函数会更加的灵活,多变
? 参数分为形参和实参:
一:形参
? 参数名写在定义函数括号里面的叫做形参 – 形式参数,它并不是真正的参数
def qiao(a,b): #此时a和b都是形参 -- 是未知值,需要我们去传入具体的数据 -- 实参
return a-b
(1)必备参数:
? 凡是写在定义定义函数括号里面的都是必备参数(除了*
)
def qiao(a,b): #此时a和b都是必备参数
return a-b
print(qiao(400,200) #此时里面的数据就是实参
? 注意: 有多少个形参必备参数,就有多少个实参,多或者少都会报错
? 必备参数一定要写在所有类型参数的最前面,如果写在了后面,会报错
(2)默认参数:
? 有默认值,可以不用传入实参,使用默认的那个值;如果传了实参,则使用传入的那个实参的值
def qiao(a,b=200): #此时a是必备参数;b是默认参数
return a-b
print(qiao(600))
? 注意: 当形参有默认参数时,如果使用的是默认参数,则注意形参中的未知值决定是否需要实参
? 当与不定长参数一起使用时,要写在不定长参数的前面,不然,会报错
(3)不定长参数:
? 带有*
*args
**kwargs
,实参个数不固定,可有可无可多传也可不传
*
和**
表示不定长 默认args
和kwargs
表示不定长参数的参数名,也可以自定义名字*args
和**kwargs
会区分实参的形式,经过区分然后去接收*args
和**kwargs
两者的区别:? *args
会把接收到的位置参数存到元组,args
是元组类型
? **kwargs
会把接收到的关键字参数存入字典,kwargs
是字典类型
#计算出给定数据的相加和
def qiao(*args): # *args会把接受到的数据参数存到元组,args是元组类型
s = 0
for i in args:
s += i
return s
print(qiao())
print(qiao(12,43,76,90)) #可以直接将函数打印输出
yue = qiao(12,42,78,0,64) #也可以将函数赋值给变量名在打印输出
print(yue)
#计算出给定数据的相加和
def qiao(a,*args): # a是必备参数,*args是不定长参数
s = 0
for i in args:
s += i
return s
print(qiao(12,43,76,90)) # 一个必备参数只会接收一个对应位置上的值;其余参数都被*args接收
#最后的运算结果会自动的把必备参数所对应的那个实参给排除掉,不参与相加
#剩下的由*args接收的参数自动相加
二:实参
? 写在调用函数括号里的,有具体的值,是真正的实际参数
(1)位置参数:
? 只要是单个的数据就都是位置参数,位置参数根据位置传参
def qiao(a,*args):
s = 0
for i in args:
s += i
return s
print(qiao(12,43,76,90)) #里面的参数都是位置参数
? 注意: 传入实参时注意位置参数一定要在关键字参数的前面
(2)关键字参数:
? 以变量赋值的形式的参数,关键字参数以参数名传参
def qiao(a,*args,**kwargs):
s = 0
for i in args:
s += i
return s
print(qiao(12,43,76,90,hjk="ertyui",yui=67,op=99)) #前四个参数是位置参数,后三个是关键字参数
? 注意: 当关键字参数中有与默认参数相同名字的变量名时那么变量名所赋的值会给到默认参数
? 当用关键字参数去传值时,要具体到参数的名字,此时是根据形参名去接收值,而不是位置
def qiao(a,b=10):
return a + b
print(qiao(a=46,b=90))
def qiao(a,b=20,*args,**kwargs):
print(a,b,args,kwargs)
print(qiao(12,43,76,90,hjk="ertyui",yui=67,op=99)) #此时默认参数b接收的值是43
? 在自定义调用函数运行完毕后,Python会默认返回一个None
,返回值也可以自己定义,返回值可以是任何类型,数据,甚至是表达式,返回值是根据自己的需求去定义的
自定义返回值格式:
def 函数名(参数):
函数要去实现的功能代码
return 返回值 #返回数据,结束自定义函数
#调用函数
函数名(参数)
? 注意: return
属于结束语句,且return
在程序中只执行一次,写在return
后面的代码无意义,待return
执行完后,其后面的代码不会再去执行了,所以要把return
放到最后
? 如果有返回值的话,要用print()
函数将其打印在控制台上,不然控制台不会显示结果
def qiao():
name = "qiaoyue"
age = "未知"
return 10
print(qiao()) #控制台上显示10这个数字
? 在函数的里面定义另外的一个函数
def one():
print("这是外层函数")
def two():
print("这是内部函数")
one()
? 注意: 在此时不会执行内部函数,只会执行外层函数,因为内部函数two是存储在one函数里面的,属于局部函数,在one函数外面是访问不到的,只能应用在one函数的内部
def one():
print("这是外层函数")
def two():
print("这是内部函数")
two() #在函数内部被访问
? 注意: 在函数内部调用其它的函数不是函数的嵌套,在函数内部去定义子函数才是函数的嵌套
(1)局部变量:只能在当前函数内部中使用,离开这个函数便访问不到了
def s():
a = 1 + 2 #这个a就是一个局部变量
print(a)
? 注意: 当离开这个函数再去访问局部变量时,会发生报错
(2)全局变量:可以在整个程序中使用,在这个程序中都可以被访问
b = 1+2 #这个b就是一个全局变量
def s():
c = 1 + b
print(b)
print(c)
print(s)
global函数:提高局部变量的作用域,将其声明为全局变量,让其在函数外也可以被访问的到
global函数的语法格式:global 局部变量名
#错误使用被声明的局部变量
def qiao():
name = "qiaoyue"
global name #将name声明为全局变量,提升其权限
age = "未知"
print(name)
? 注意: 在此时name依旧无法被访问,因为name在函数的内部,在没有调用这个函数前,是运行不到name这个变量的,所以就算将其声明为全局变量也要受到函数的限制,注意在使用被声明过的局部变量时,要先调用这个局部变量所对应的函数
#假正确使用被声明的局部变量
def qiao():
name = "qiaoyue"
global name #将name声明为全局变量,提升其权限
age = "未知"
qiao()
print(name)
? 注意: 此时name依旧无法被访问,因为当执行完这个函数的时候,函数内部的数据就会被释放掉,在函数体里面的代码相当于是一段临时代码,用完就会在函数内部空间被释放。所以global
函数要写在被声明的局部变量之前,这样才会让其在函数内部和函数外部的空间中都有其存在
? 使用global
函数:要先声明那个变量,在去定义那个函数里面的内容,这样才会有作用
#真正确使用被声明的局部变量
def qiao():
global name #将name声明为全局变量,提升其权限
name = "qiaoyue"
age = "未知"
qiao()
print(name)
? 当一个函数可以作为参数传给另外一个函数,或者一个函数的返回值为另外一个函数(若返回值为该函数本身,则为递归)二者满足其一则为高阶函数
? 当函数名作为参数进行传递的时候,返回的是这个传入的函数在内存中的地址
def one():
print("这是普通的函数")
def high(one): #此时并不完全算高阶函数,one只是一个可以任意命名的形参,当我们往这个形参里面传入的参数是一个函数名的时候才算是高阶函数
pruint("这是高阶函数")
high(40) #此时依旧是普通函数
high(one) #此时才是高阶函数,注意不要加上括号,加上后就不是传参了,而是对这个函数的调用
? 注意: 函数名加括号为调用,再去传给其它函数时会发生错误;不加为查看该函数在内存中的地址
使用高阶函数 – 把函数当成当成另一个函数的参数进行传递:
def one():
print("这是普通的函数")
def high(canshu): #此时接收的是one函数的地址.2
print("这是高阶函数")
canshu() #此时是对one函数的调用.3
high(one) #此时传入的是one函数,准确的说应该是访问one函数的地址。1
? 注意: 内部函数代码是最后才去执行的,先执行创建函数并赋予这个函数在内存空间中的地址,再执行high函数的调用,然后去接收普通函数one函数的地址,再执行one函数的调用(在这个阶段one函数会返回的就不在是它的函数地址了,而是one函数内部运行的代码结果)最后再执行其内部代码 – 内部代码先执行高阶函数,也就是外部函数;再执行普通函数,也就是内部函数。
? 重点是最后传进去的要是这个函数名,高阶函数的形参名并不重要,最后都会变成函数名。
使用高阶函数 – 把函数当成另一个函数的返回值:
def one():
print("这是普通的函数")
def high(canshu):
print("这是高阶函数")
return canshu
print(high(one))
? 注意: 此时程序执行完成之后高阶函数high返回的结果只是其本身的内部代码运行的结果和one函数的地址。因为在high函数中形参接收到one函数的地址,后面的return``语句又把这个地址直接返回被print(high(one))这条代码给接收到
,所以one函数内部代码并没有去运行
def one():
print("这是普通的函数")
def high(canshu):
print("这是高阶函数")
return canshu
print(high(one)())
? 注意: 此时程序执行完成之后高阶函数high返回的结果是其本身的内部代码运行的结果和one函数内部代码运行的结果,和返回值None。因为一个地址在给它加上一个括号的意思是调用,而在最外层还有一个print()
函数,意思是输出one函数调用的一个结果,而在one函数中并没有给它设置返回值,所以返回的是None
print(high(one)())
#这条语句等价于:
a = high(one) #这条语句的意思是:变量名(相当于函数的返回值 -- 地址) = 函数名(形参 -- 另一个函数名)
print(a()) #函数的返回值(地址)加上括号等同于函数名加上括号也就是回调
map()函数:把序列中的每一个元素作用于函数上,最终返回
map()函数的语法格式:map(函数,序列) 传入一个函数和一个序列,用来作映射
def ccc(x):
return x + 2
print(map(ccc,[23,46,89,66])) #最后输出的结果是一个map对象
? 注意: map()
函数的两个参数是必须要传的,并且map()
函数输出的是一个map
类型的对象和它在内存中的地址,我们是不能查看到内部的数据的,因为map()函数本身是一个迭代器,并不是一个容器,迭代器本身并不是存储数据的,只生成数据。但可以将其转换成其它的类型去查看生成的数据
def ccc(x):
return x + 2
print(list(map(ccc,[23,46,89,66]))) #将其转换成列表类型
filter()函数:把序列中的每一个元素作用于函数上,如果函数返回的结果是True,那么filter()函数会过滤掉函 数返回结果为False的
filter()函数的语法格式:filter()(函数,序列) 传入一个函数和一个序列,用来作过滤
def aa():
if aa > 10:
return True
print(list(filter(aa,[45,2,7,19,88]))) #filter()也是一个迭代器
? 注意: filter(
)函数的两个参数是必须要传的
sorted()函数:排序,对任何单一的序列类型中的单一类型元素进行排序
? 当sorted()函数排序的是数字时:按照0~9的顺序排序
? 当sorted()函数排序的是字母时:按照a~z的顺序排序
? 当sorted()函数排序的是数字+字母的多种字符串元素时:看第一个字符,先排数字,在排字母
? 当需要进行其它的排序时,按照需要填入函数名
sorted()函数的语法格式:sorted(序列,key=) key接收的是一个函数名 – 不带括号,指定排序方式的函数
a = "fghjcvbdfgh"
print(sorted(a))
b = ("aewfef","45","ijnhyu","90")
print(sorted(b))
? 注意: 当进行多种类型排序时,会发生报错,如:字符串+数值类型
b = ("aewfef","45","ijnhyu","90")
print(sorted(b,key=len)) #按照字符元素长短进行排序,短在前,长在后
print(sorted(b,key=len,reverse=True)) #长在前,短在后
#用列表中的sort()进行排序:
a = [
{name="qi",age=12}
{name="ao",age=16}
{name="yue",age=18}
]
def ni(x):
return x["age"] #返回它对应的年龄,让其根据字典中的年龄大小进行排序
a.sort(key=ni) #因为列表中的是序列而不是单一的元素,且字典与字典之间无法进行比较,所以要用函数去指定排序的方式
print(a)
#用sorted()方法对字典进行排序:
print(sorted(a,key=a))
? 如果一个函数在其内部调用自身本身,那么这个函数就是递归函数
? 递归函数必须包含递归出口和递归体:
(1)递归出口:递归不可能一直进行下去,通常在问题的规模减小到一定程度后就需要结束递归。而这个终止条 件就是递归出口,递归出口必须保证在问题规模达到最小时结束递归,否则会导致无线递归,进 而使程序崩溃
(2)递归体:递归体是递归函数的主要部分,它描述了如何将一个规模最小的问题进一步分解,直到问题规模达 到递归出口所定义的大小,然后直接输出结果
#不完整递归,会报错,这里报错的原因是因为没有给递归出口,导致其一直运行下去
def a(x):
print(x)
return a(x-1)
print(a(5))
? 注意: 递归是有最大深度的,最大只能到1000,当递归次数太多时,会造成内存溢出
#完整递归
def a(x):
if x == 0: #递归出口
return x
print(x)
return a(x-1) #递归体(调用自身函数),使递归无限接近出口
print(a(5))
? 匿名函数也是自定义函数,但是是没有名字的函数,匿名函数只能实现一些简单的功能
匿名函数的语法:用 lambda 去定义,使用时需要用到变量去接收
lambda 形参:表达式/函数的返回值
#计算两个数相加
#用函数实现
def a(x,y=100):
return x+y
print(a(2,6)) #计算2加6
#用匿名函数实现
a = lambda x,y=100:x+y
print(a(2,6))s
#另一种语法格式
a = (lambda x:x)("Like You") #传入"Like You"并赋值给x最后在传给x
print(a)
? 注意: 在匿名函数中形参可以有很多个,但表达式/返回值只能有一个
#用不定长参数实现
a = lambda *args,**kwargs:sum(args) #可以接收任何参数,无论传什么传多少都可以接收
print(a(2,4,2,5,name="like"))
#在匿名函数中做判断
a = lambda x,y:y if y>x else x
print(a(56,78))
? 闭包是高阶函数的一种实现方式,是一个特殊的高阶函数,闭包可以延长函数中局部变量的生命周期,可以将外层函数内的局部变量持久的保存在内存中,即使外层函数的空间被释放,这些变量也不会销毁,而是会被保留直到闭包被销毁
如何实现闭包:
? 1.嵌套函数
? 2.外层函数返回内层函数的地址
? 3.内层函数使用外层函数的变量
#闭包函数的实现,要同时满足以上三点
def a(x):
def b(y):
return x+y
return b
qiao = a(55) #返回值 = 函数名() 所以qiao接收到的就是函数b的地址
print(qiao(78)) #地址名加括号相当于函数的调用
? 注意: 闭包一定要有至少一个参数,用来接收函数地址
? 装饰器是一个非常强大的工具,它可以在不改变原函数的基础上,给函数增添新的功能,装饰器本质上就是一个闭包函数,接收一个函数作为参数,并返回一个修改后的函数
#原函数
li = []
def yue(name):
li.extend(name)
print(li)
yue("gugu")
#给这个函数增添查询的功能 -- 装饰器
li = []
def qiao(ze): #ze接收传入的参数;ze这个形参就是用来接收主函数的
def aa(name):
ze(name)
print("开始查询")
if name in li:
print("已存在")
return bb
#将装饰器加装到原函数的身上
@qiao #调用装饰器,接收一个函数并返回一个新的函数 yue = qiao(yue);把yue函数当成参数传递给qiao函数
def yue(name):
li.append(name)
print(li)
yue("gugu") #这里是在调用aa函数,"gugu"为aa的参数
? 注意: 装饰器一定是一个闭包,且一定要写在要装饰的函数的函数名上面
? 调用装饰器: @外层函数名
? 迭代就是依次访问可迭代对象元素的过程,把这样的过程称之为遍历也叫迭代
(1)判断是否为可迭代对象
? 可迭代对象是指可以被 for循环 遍历的对象,在Python中,dir()
可以查看对象的所有属性和方法,只要实现了 iter()
方法,就可以被称为可迭代对象
print(dir([1,2])) #查看列表所拥有的一些属性和方法,如果里面发现有iter()方法,说明它就是一个可迭代对象
? 注意: iter()
是将可迭代对象转换为迭代器,而不是将任意的类型转换为迭代器
from collections.abc import Iterable
a = iter([23,455,88]) #将列表转换为迭代器
print(isinstance(a,Iterable))
? 使用内置函数 isinstance()
来判断一个对象是否是可迭代对象,或用来判断某一对象是什么类型
from collections.abc import Iterable #此函数使用时要导入
print(isinstance("tfyudxectuy",Iterable)) #判断此类型是否为Iterable类型,是为True,不是为False
? 注意: Iterable
是迭代器的意思
from collections.abc import Iterable
print(isinstance(123,int)) #判断123是否为int类型
? 注意: 容器都是可以被迭代的
? 只要是能被for
循环所遍历的就都是可迭代对象
(2)迭代器的本质
? 迭代器是Python中访问元素的方式,它可以记住遍历的位置,直到所有的元素被访问结束
? 迭代器与可迭代对象是有区别的,可迭代对象可以理解为是存储多个元素的容器,但是迭代器本身并不存储数据,而是等到用到时才生成数据,因此,迭代器要比容器更加的节省内存
? 迭代器本身是通过 next()
函数去获取下一条数据,for
循环的本质就是将可迭代对象转换为迭代器,然后调取next()函数依次取值
#for循环的原理
li = [24,4,5,885,25,240]
lion = iter(li) #通过一个变量拿到这个列表的迭代器
while True:
try: #异常捕获
next(lion) #通过next()函数取值
except StopIteration: #捕获StopIteration异常
break
? 注意: 迭代器中无法用过索引去取值,因为迭代器中的数据是一个一个生成的,索引索取不到,只能够通过next()
函数去一个一个获取到其中的值
li = [24,4,5,885,25,240]
lion = iter(li) #通过一个变量拿到这个列表的迭代器
print(next(lion)) #next()函数获取到迭代器中的第一个值并打印输出
print(next(lion)) #next()函数获取到迭代器中的第二个值并打印输出
print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
for i in lion: #从第三个值开始获取
print(i)
? 注意: next()
函数有记忆力,已经访问过的元素就不会在重复去访问了,因为for
循环本身就是通过调取next()
函数去取值,而next()
函数已经取过两个值了,所以不会再次去访问这两个值了,这就是为什么迭代器能够记住当前访问的位置
? 生成器是特殊的迭代器,在需要数据时才会生成值,本身不会去存储数据,从而节省内存,生成器的创建方式要比迭代器简单很多,在Python中使用 yield 关键字来定义一个生成器函数
def we():
yield 1 #返回1这个值给到生成器,并暂停执行
yield 2 #第二个next()函数取值,因为有yield,又再次暂停执行
yield 3
x = we() #通过一个变量获取到生成器对象
print(next(x))
print(next(x))
? 注意: 如果函数中有yield
这个关键字,那么这个函数就是生成器函数
? 生成器函数不能通过普通的函数调用获取值,而要通过next()
函数去获取生成器函数里的值
? 生成器函数会通过yield
这个关键字自动暂停执行,暂停的只是函数体,不耽误后续代码
? 生成器的第二种创建方式:(表达式 for 变量 in 可迭代对象)
from collections.abc import Iterable
a = (i for i in range(56,79))
print(a)
print(isinstance(a,Iterable))
print(next(a))
? (1)文件操作包含:打开;关闭;读;写;复制等
? (2)文件操作的作用:读取内容;写入内容;备份内容等,把一些内容或数据给存储起来,可以让程序在下一次执行的时候直接使用,而不必重新制作一份,省时省力
? (3)文件与数据库的区别:
? 相同点:都是用来存储数据且对数据进行持久化的存储
? 不同点:文件操作是在本地进行持久化存储;而数据库是一个远程的持久化
? (4)文件的路径:
? 相对路径:同级路径,在当前文件夹下通过名称去查找
e.g. 上一级的文件名\\01.txt
? 绝对路径:从当前磁盘下的根目录去查找
e.g. D:\文件名\文件名\01.txt
? 一:通过 open(filename,打开文件的模式,encoding = "utf-8")
函数:打开本地的文件或文件夹
? filename
参数:指定文件的路径(相对路径或绝对路径),要把所要查找的具体文件名也写上
? encoding
参数:指定文件的编码,默认 Utf-8
编码
? 注意: open()
函数只会帮你把文件打开,不会帮你把文件关闭
文件的基本操作:
模式 | 描述 |
---|---|
w | 打开一个文件只用于写入;如果该文件已存在则打开文件且原有内容会被删除,从头开始重新写入;如果该文件不存在则创建新文件 |
r | 以只读的方式打开文件,只能打开已经存在的文件,光标会放在最前面 |
a | 打开一个文件用于追加;如果该文件已存在,光标会放在文件的结尾追加写入,也就是新的内容将会被写入到已有内容之后;如果该文件不存在则创建新文件进行写入 |
w+ | 在 "w" 模式的基础上附加读取(read)权限 |
r+ | 在 "r" 模式的基础上附加写入(write)权限,r+ 的本质就是对原本内容的覆盖 |
a+ | 在 "a" 模式的基础上附加读取(read)权限 |
wb | 以二进制的格式打开一个文件只用于写入;如果该文件已存在则打开文件且原有内容会被删除,从头开始重新写入;如果该文件不存在则创建新文件,一般用于非文本文件 |
rb | 以二进制的格式打开一个文件用于只读,文件的光标会放在最前面,一般用于非文本文件 |
ab | 以二进制的格式打开一个文件用于追加;如果该文件已存在,光标会放在文件的结尾追加写入,也就是新的内容将会被写入到已有内容之后;如果该文件不存在则创建新文件进行写入 |
wb+ | 以二进制的格式打开一个文件用于读取和写入,如果该文件已存在则打开文件且原有内容会被删除,从头开始重新写入;如果该文件不存在则创建新文件,一般用于非文本文件 |
rb+ | 以二进制的格式打开一个文件用于读取和写入,文件的光标会放在最前面,一般用于非文本文件 |
ab+ | 以二进制的格式打开一个文件用于追加;如果该文件已存在,光标会放在文件的结尾追加写入,也就是新的内容将会被写入到已有内容之后;如果该文件不存在则创建新文件用于读取和写入 |
? *注意:*当在 open()
函数中不写入模式时,那么会自动默认为 "r"
模式
? 用于非文本文件指的是图片;视频等,多用于爬虫
(1)read()
读取:"r"
模式只支持读取
? "r"
模式只能够打开已经存在的文件,无法进行新建操作,光标在最前面
? read()
读取返回的数据类型是字符串
#用相对路径来完成读取:
a = open("fi.txt","r",encoding = "utf-8")
#用open()函数打开的内容是文件的一个可迭代对象,并不会直接把内容给到你
#用变量a去接收,此时a是一个文件流;文件对象
print(a.read())
#read()是用来读取文件里面的一个内容
#用绝对路径来完成读取:
b = open(r"D:\asd\fgh\wem\fi.txt","r",encoding = "utf-8")
print(b.read())
? readline()
和 readlines()
读取:
? readlines()
默认读取的是整个内容,读取的是一个字符串,按照行的方式把整个文件中的内容进行一次性读取,并且返回的是一个列表,其中每一行的数据为一个元素
? readline()
是一行一行读取的,读取的是光标所在行,一般用于 for
循环
#读取所有内容
a = open("fi.txt","r",encoding = "utf-8")
print(a.readlines())
#读取第一行
a = open("fi.txt","r",encoding = "utf-8")
print(a.readline())
(2)write("要写入的内容")
写入:write
只能写入字符串
? "w"
模式进行写入:
? 如果这个文件名已经存在,用 "w"
模式打开则会清空文件中的内容
? 如果这个文件名不存在,"w"
模式则会进行新建
? 不管文件是否存在,只要用"w"
模式打开,以往的内容都会被新输入的内容给替换掉
#用相对路径来完成写入:
a = open("fi.txt","w",encoding = "utf-8")
#用open()函数打开的内容是文件的一个可迭代对象,并不会直接把内容给到你
a.write("Hello!")
#write()是用来在文件中写入一个内容
? 注意: write()
没有返回值,直接去文件中查看写入的内容即可
? "a"
模式用于追加:
? 当文件名不存在时,"a"
模式则会进行新建
? 当文件名存在时,用 "a"
模式可以在原来内容的末尾去添加新内容,不会发生替换和清空,光标在最后面(光标在哪个位置就从哪个位置开始写;但如果光标在最前面,则会发生清空替换)
#用相对路径来完成写入:
b = open("fi.txt","a",encoding = "utf-8")
#用open()函数打开的内容是文件的一个可迭代对象,并不会直接把内容给到你
b.write("I like you!")
#write()是用来在文件中写入一个内容
(3)用 "w+"
进行写入读取操作:
a = open("fi.txt","w+",encoding = "utf-8")
print(a.read()) #此时无法进行读取,因为"w+"模式是在"w"模式的基础上进行操作的,而"w"模式会进行清空操作
a = open("fi.txt","w+",encoding = "utf-8")
a.write("I like you")
print(a.read()) #此时依旧无法进行读取,因为光标问题,在写入内容之后光标已经在最后面了,所以读取不到内容
? 此时就用到了seek()
函数:移动光标,通过设置里面的参数从而控制光标的移动位数
a = open("fi.txt","w+",encoding = "utf-8")
a.write("I like you")
a.seek(0) #将光标移动到最前方
print(a.read()) #此时可以完成读取,读取到的内容为新写入的内容,因为以往的内容已经被"w"模式给清空了
? 注意: 每次写入时,“w+
” 模式都会将以往的内容给清空覆盖
(4)用 "r+"
进行写入读取操作:
? tell()
函数:查看当前文件的光标位置
? close()
函数:关闭当前文件
a = open("fi.txt","r+",encoding = "utf-8")
a.write("I like you")
print(a.tell())
a.seek(0)
print(a.read(6)) #读取6个位置
a.close()
? 注意: 多注意光标位置,如果不对就进行调整
? 当重复执行时一样的内容时,"r+"
模式不会多次写入,也不会对以往的内容进行覆盖
(5)用 "a+"
进行写入读取操作:
a = open("fi.txt","a+",encoding = "utf-8")
a.write("I like you")
print(a.tell())
a.seek(0)
print(a.read(9)) #读取9个位置
a.close()
? 注意: 当重复执行一样的内容时 "a+"
模式会多次写入,但不会覆盖原本写入的内容
? 二:通过 with open(文件的路径,打开文件的模式,encoding = "指定的文件编码") as f:
? with
是上下文管理器,当文件打开,带缩进的代码执行完毕后,会自动把文件关闭
? f
是临时变量名,只在 with open()
里有用,出了 with open()
再用会报错
with open("fi.txt","r+",encoding = "utf-8") as f:
print(f.read())
f.write("I like you")
? 注意: 缩进和光标的位置,一直打开文件会占用内存空间,如果用 open()
函数的话记得关闭文件
备份一个文件:
#复制操作
a = "fi.txt"
with open(a,"r",encoding = "utf-8")as i:
b = i.read()
print(b)
#新建文件并粘贴的操作
with open("beifen.txt","w",encoding = "utf-8")as i:
i.write(b)
题目:张三办了一张银行卡,里面没有一分钱,现在他要进行存钱和取钱的操作
1.编写两个函数:
(1)存钱函数:save_money()
(2)取钱函数:get_money()
2.创建一个bank_card.txt的文本文档,充当银行卡
要求:
1.当调用存钱函数时,我们输入的金额将会存储在bank_card.txt银行卡中
2.当调用取钱函数时,我们输入的金额将会在bank_card.txt银行卡中扣除
#办银行卡
with open("bank_card.txt","w",encoding = "utf-8") as i:
i.write("0") #没有一分钱,表示开卡成功
#创建存钱函数:save_money()
def save_money(money): #传入参数(存入的金额)
with open("bank_card.txt","r+",encoding = "utf-8") as f: #在存钱之前要先读取知道原本有多少钱,在与存入的钱进行累加
look = float(f.read()) #此时要先进行读取,在与存入的数字进行累加,最后在去写入;因为相加是变量与变量之间所以要把读取的内容存入到变量中
look += money #读取到的金额加上存入的金额
f.seek(0) #要时刻注意光标的位置
save = float(f.write(f"{look}")) #将金额存入到银行卡中
print(look)
save_money(678.9) #调用函数进行存钱操作
save_money(567)
#创建取钱函数:get_money()
def get_money(money): #传入的参数(取出的金额)
with open("bank_card.txt","r",encoding = "utf-8") as f: #读取
'''
此时这里不能使用r+因为r+的本质是覆盖,而取钱会造成钱的数量减少,覆盖不到位的情况
也不能使用w+因为w+会先造成清空的操作
这里应先进行两次操作,先读取,再用读取到的金额减去取出的金额,最后再写入
'''
look = float(f.read())
with open("bank_card.txt", "w", encoding="utf-8") as f: #写入,此时已经将数据读取并保存到变量中了,就算清空也没有关系了
if money > look:
print("您的银行卡余额不足,请重新输入~~~")
f.write(f"{look:.1f}")
print(f"{look:.1f}")
else:
look -= money
# f.write(str(look))
f.write(f"{look:.1f}") #写入时后面仅保留一位小数
print(f"{look:.1f}") #输出时后面仅保留一位小数
get_money(10000) #调用函数进行取钱并查看剩余金额
? 在 Python 中文件和文件夹的操作要借助 os
模块里面的相应功能,os
模块是内置模块,无需安装
os 模块的使用:
(1)导入模块
import os
(2)文件重命名
os.rename(目标文件名,新文件名)
(3)删除文件
os.remove(目标文件名)
(4)创建文件夹
os.mkdir(文件夹名字)
(5)删除文件夹
os.rmdir(文件夹名字)
(6)获取当前文件目录路径
os.getcwd()
(7)改变默认目录
os.chdir(目录)
(8)获取目录列表
os.listdir(文件目录)
(1)类
? 类是对一系列具有相同特征和行为的事物的统称,是一个抽象的概念,不是真实存在的事物,而对象就是根据类来创建的,有类才有对象
? 特征 --> 属性
? 行为 --> 方法
类的创建:
class 类名():
特征 --> 属性:变量
行为 --> 方法:函数
pass
? 注意: 类名要满足命名规范,最好遵循驼峰命名习惯
#定义一个类
class Dog():
#特征(属性):用变量去描述这个事物所具有的特征
head = 1 #类属性
#行为(方法):用函数去描述行为,实例化方法
def eat(self): #self是必备参数,是自带的,表示实例对象本身
print("吃")
def drink(self):
print("喝")
print(dog) #此时只有类没有对象它是没有实质性意义的
? 注意: 当有多个特征或行为时,就定义多个变量或函数,当然,特征与行为并不做固定要求,可以有也可以没有;但是一个规范的类,行为都是要有的
? self
不写会报错;self
表示实例对象 --> self
是实例对象;实例对象也是 self
。所以无需给 self
传参。self
是动态的,哪个对象调用它,它就是哪个对象
(2)对象
? 对象是类所创建出来的真实存在的事物
对象的创建:实例化对象
one = Dog() #实例化对象:dog是一个类的统称;而one是一个具体的实例
print(one)
one.eat() #通过实例对象访问类里面的方法(调用类里面的方法)
print(one.head) #通过实例对象访问事物的特征
? 注意: 通过一个类可以去创建无数个实例对象
? 注意区分属性和方法,属性不带括号,而方法带括号
#在外部定义属性
one.xxx = 10 #实例属性
print(one.xxx)
? 注意: 虽然可以在外部定义属性,但是不建议,因为那是实例对象的属性,并不是类的属性, 类属性是所有的实例对象都可以访问到的,是公共的属性;而实例属性只有当前的实例对象才可以访问到,是私有属性,其它的实例对象访问会报错
? 方法只能定义在类里,不可在外部添加
? 在Python中,__xx__()
的函数叫做魔法方法,指的是具有特殊功能的函数,当它满足条件时会自动执行
__init__()
方法:初始化对象
class Dog():
az = 4
def __init__(self): #在实例化对象的时候自动执行,不需要单独调用
print("正在初始化~~~")
def eat(self):
print("吃")
dahei = Dog() #只要实例化对象就会触发执行 __init__() 魔法方法
print(dahei.az)
dahei.eat()
#定义实例属性:
# 1.实例对象.属性名 = 值
# 2.在类里定义实例属性 -- 使用 __init__() 魔法方法定义:
class Dog():
az = 4
def __init__(self,name1,price1): #name1与price1都是形参
self.name = name1 #self就是实例对象,所以相对于 -- 实例对象.属性名(定义的名字) = 值
self.price = price1 #这里的name1与price1是用来接收传入形参的具体的值
print("正在初始化~~~")
def eat(self):
print("吃")
dahei = Dog("边牧",80000000)
dahei = Dog(name1="边牧",price1=80000000)
print(dahei.name)
print(dahei.price)
? 注意: self
这个参数不用传参,但定义的其它参数是一定要去传参的,不然会报错
? 当需要用到实例对象时,使用第2种方法,第1种方法的代码安全性较低,且与封装相违背
__str__()
方法:
class Dog():
az = 4
def __init__(self,name1,price1):
self.name = name1
self.price = price1
print("正在初始化~~~")
def __str__(self): #当输出实例对象的时候自动执行
# return self.name #返回指定的值给到实例对象
return "DuDu" #也可以返回任意的值
def eat(self):
print("吃")
dahei = Dog("边牧",80000000)
print(dahei) #输出实例对象
__del__()
方法:
class Dog():
az = 4
def __init__(self,name1,price1):
self.name = name1
self.price = price1
print("正在初始化~~~")
def __str__(self):
return self.name
def __del__(self): #当实例对象被销毁的时候自动执行
print(f"{self.name}被销毁了———")
def eat(self):
print("吃")
dahei = Dog("边牧",80000000)
print(dahei)
? 注意: 当程序运行结束后,一些用不到的数据会被Python自动销毁掉(或者手动用 del
语句销毁),此时就会触发 __del__()
方法
? 面向对象编程有三个特性:封装;继承;多态
(1)封装
? 在面向对象的程序设计中,某个类把所需要的数据(类的属性)和对数据的操作(类的行为)全部都封装在类中,分别称为类的成员变量和方法(成员函数),这种把成员变量和成员函数封装在一起的编程特性称为封装
(2)继承
? 继承是指可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行拓展
(3)多态
? 多态指的是一类事物有多种形态。如:
? 序列类型的多种形态:字符串;列表;元组等
? 动物类型的多种形态:猫;狗;猫头鹰;乌鸦等
? 多态性是允许你将父对象设置成为和一个或更多的它的子对象相等的技术,赋值后,父对象就可以根据当前赋值给它的子对象的特性以不同的方式运作
? 封装分为数据封装和方法封装
(1)数据封装:就是把属性中具体的值给隐藏起来,对外部显示的只有属性名
? 封装数据的主要原因是保护隐私
(2)方法封装:就是在外部只需要通过方法名就能调用方法,不需要了解方法中具体的细节
? 封装方法的主要原因是隔离复杂度
? 封装的两个层面
(1)第一层面的封装:
? 创建类和对象时,分别创建二者的名称空间,只能通过 类名.
或 对象.
的方式访问里面的名字
(2)第二层面的封装:
? 在类中把某些属性和方法隐藏起来,或者定义为私有,只在类的内部使用,在类的外部无法访问,或者留下少量的接口函数供外部使用
class People(): #类是一个模型,不可以直接访问到行为,只有实例对象才可以调用方法
#属性和方法是封装在类里面的
age = 18 #类属性 --> 用变量定义:是对于事物特征的描述;这里的类并没有通过实例对象去定义,所以是类属性;任何对象都可以访问到
#通过魔法方法定义实例属性
def __init__(self,name): #因为定义了一个形参,所以在后面实例化对象时一定要传参
self.name1 = name #self == i;self表示实例对象本身,也就是实例对象。实例对象.属性名
def eat(self): #方法 --> 用函数定义:是对于事物行为的描述
self.name1 = "张三" #在这里也可以定义实例属性,只要是通过 实例对象.属性名 去定义的就可以
print("吃")
#通过对象去定义实例属性
i = People("张三") #实例化对象
i.name1 = "张三" #i定义的实例属性只有i可以访问到
print(i.name1)
#现在的属性可以通过类名访问或修改;还可以通过实例对象访问或修改,这样的话会使这个类很不安全,把数据完全的暴露在外面
#通过类名访问属性
print(People.age)
#通过类名修改属性
People.age = 20
print(People.age)
#通过实例对象访问属性
print(i.age)
#通过实例对象修改属性
i.age = 30
print(i.age)
#私有化,类的私有属性:将类中的属性与方法封装起来就叫封装;封装是为了不让数据暴露在外面,被外部所修改
class People():
__age = 18 #定义私有属性:在变量名的前面加上两个下划线;私有属性只能在类的里面去使用,私有属性在外部不可被访问或修改,不然会发生报错
def eat(self):
print("吃")
def get(self): #定义的函数接口,拿到age值,可以在外部调用该方法去访问私有属性,但不能修改
print(self.__age) #函数接口就是间接的去访问
i = People()
#print(i.__age) #此时再去访问属性会发生报错
i.get() #通过实例对象去调用这个接口,可以访问但不能做修改
People().get() #也可以直接通过类去调用这个接口,可以访问但不能做修改
#私有化:类的私有方法:存储重要数据,不让别人看到
class People():
age = 18
def __hob(self): #定义私有化方法,禁止别人访问,在函数名前加上两个下划线;若想要访问,也需要在定义一个函数接口
print("xxx")
def a(self): #定义的函数接口
return self.__hob() #return后面可以放任何数据,此时返回的是执行__hob()函数
i = People()
i.a() #通过实例对象在外部调用函数接口,可以访问但不能做修改
People().a() #直接通过类去调用这个函数接口,可以访问但不能做修改
? 注意: 个人理解:封装就是让数据私有化,让数据更加的安全
? 当我们定义一个class
的时候,可以从某个现有的class
中继承属性和方法,新的class
称之为子类,而被继承的class
称之为父类;基类或超类。父类可以被子类继承,但子类不能继承其它的子类
? 在Python中,object
类是所有类的父类,不管写没写,都会自动继承;Python3中默认继承都是object
类,object
类是顶级类;终极类或基类,只要定义一个类都会自动继承Python中的object
类;而其它的子类也叫做派生类
class 派生类名(object): #当括号为空时,默认继承object类
pass
(1)继承的特点
? 在Python中,如果父类和子类都重新定义了构造方法__init__( )
,在进行子类实例化的时候,子类的构造方法不会自动调用父类的构造方法,必须在子类中显示调用
? 如果需要在子类中调用父类的方法:需要以 父类名.方法名(self)
这种方式调用,以这种方式调用的时候,注意要传递 self
参数过去;另一种方法是使用super()
,直接使用 super().方法名
? Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去父类中找)
? 对于继承关系,子类继承了父类所有的公有属性和方法,可以在子类中通过父类名来调用,而对于私有的属性和方法,子类是不进行继承的,因此在子类中是无法通过父类名来访问的
? Python支持多继承,能够让一个子类有多个父类
? 如果有多个父类,多个父类名之间用逗号隔开
? 如果子类没有重新定义构造方法 __init__()
,它会自动调用第一个父类的构造方法,以第一个父类为中心
? 如果子类重新定义了构造方法,需要显示去调用父类的构造方法,此时调用哪个父类的构造方法由你自己决定
? 注意: 上面的特点不重要,直接看下面的代码就行
(2)单继承
? 把一个类作为另一个类的父类,就是把这个类传给另一个类,这就叫做单继承;当继承后除子类中自己的属性和方法外,父类中的所有属性和方法子类也都可以使用
#一个学生继承一个老师类
class Teacher(object):
def hobby(self):
print('继承了老师的爱好-python')
class Student(Teacher): #继承关系:括号里填入被Student类所继承的类的类名,表示这个类被Student类继承
def __init__(self,name):
self.name = name
def info(self):
print("我是学生{}".format(self.name))
#实例对象,调用Teacher类中的方法
i = Teacher()
i.hobby()
#实例对象,调用Student类中的方法
f = Student("张三")
f.info()
#使用父类中的方法
f.hobby()
(3)多层继承
? 在父类中,父类继承一个父类,我将其称为祖父类;只要是被继承了那么父类中的所有方法都可以调用,包括祖父类中的方法与属性(私有属性和方法除外)
#定义父类
class Teacher():
age_ = 28
def eat(self):
print("吃")
#定义子类
class Student(Teacher):
def __init__(self,name):
self.name1 = name
age = 18
def drink(self):
print("喝")
i = Student("张三")
i.drink()
print(i.age_)
class Dog(Student):
pass #pass用来保证代码的完整性
#f = Dog() #此时运行Student类里面的 __init()__ 方法,因为Dog类中并没有写入Student类中 __init()__ 方法的name参数,所以发生报错
f = Dog("李四")
print(f.age_)
f.drink()
所有继承的关系:
在实例化对象的过程中会优先加载本类中的 __init()__
方法,如果本类中没有,就会去父类中找
父类的先后顺序:先去父类中找,如果没有的话再去祖父类中找,哪里有就运行哪里的 __init()__
方法,都没有的话会执行 object
里面的 __init()__
方法
mro()
方法:打印这个类的继承关系语法格式:类名.mro()
class miao():
def __init__(self,age):
self.xiaohuang = age
print(self.xiaohuang) #注意:在一个类的方法中访问其它类的属性或方法需要使用self关键字
def play(self):
print(f"它今年{self.xiaohuang}了")
name = "小黄"
class People(miao):
pass
print(People.mro()) #输出People类的继承关系
i = People("18")
i.play()
(4)多继承
? 一个子类可以继承多个父类
class GrandFather():
def dudu(self):
print("!!!!!!!!!")
class Father(GrandFather):
def skill(self):
print("rap")
def play(self):
print("手机")
def da(self):
print("这是Father")
class Mother():
def skill(self):
print("唱跳")
def play(self):
print("代码")
def ma(self):
print("这是Mother")
class Son(Father,Mother): #多继承,先继承前面的在继承后面的,属于同级关系,继承一个之后就不能继承另一个了;要想一起继承,就用重载方法
def __init__(self,age):
self.age = age
def play(self):
print("篮球")
# 重载:重新加载父类中的方法;当子类中的方法名和父类中的方法名同名时,依旧能够执行父类中的同名方法
super().play() #重新加载父类:super().方法名;super()方法表示父类,意思是依次调用父类的方法,不能指定类去调用;也不可调用同类方法,同类方法只能用self调用
#注意:super()方法也可以调用父类的父类,也就是祖父类
super().dudu()
Father.play(self) #这个也是重载父类的方法;记得传参self
Mother.play(self) #重载第二个父类
GrandFather.dudu(self) #重载祖父类
print("除了玩手机还会玩电脑") #在父类的基础上对本类的play()方法进行新增,这就是重载的作用
def xiao(self):
print("这是Son;年龄{}".format(self.age))
son = Son("11")
son.xiao()
son.skill() #当多个父类中的方法名同名时,优先使用最前面的父类中的方法;当所有父类中都没有这个方法名时,会发生报错
son.play() #当子类中的方法名和父类中的方法名同名时,为重写;重写方法后就不会在去执行父类中的同名方法了
son.dudu()
#注意:私有属性和私有方法不可被继承,只能通过接口去调用
? 同一种事物的多种形态,不同的形态(对象)调用同一种方法能够实现不同的效果
? 指具有不同功能的函数可以使用相同的函数名,这样就可以用一个函数名调用不同内容的函数。在面向对象方法中一般是这样表述多态性:向不同的对象发送同一条消息,不同的对象在接收时会产生不同的行为(即方法)。也就是说,每个对象可以用自己的方式去响应共同的消息。所谓消息,就是调用函数,不同的行为就是指不同的实现,即执行不同的函数;有了多态,更容易编写出通?的代码,做出通?的编程,以适应需求的不断变化!
实现步骤:
? 定义?类,并提供公共?法
? 定义?类,并重写?类?法
? 传递?类对象给调?,可以看到不同?类执?效果不同
class Animal(): #父类
def eat(self):
pass
class Panda(Animal):
def eat(self):
print('吃竹子')
class Cat(Animal):
def eat(self):
print('吃老鼠')
class Rabbit(Animal):
def eat(self):
print('吃胡萝卜')
def animal(obj): #obj是形参,在这里传入的是子类的实例化对象
obj.eat()
rabbit1 = Rabbit()
panda1 = Panda()
# 传入不同的对象,实现不同的方法
animal(rabbit1)
animal(panda1)
? 注意: 同一个方法,不同对象调用方法,实现的功能不一样,这就是多态
#定义一个矩形类,拥有两个实例属性长和宽,以及计算周长和面积的两个方法
#第一种方式
class Ju():
__chang = int(input("请输入矩形的长:"))
__kuan = int(input("请输入矩形的宽:"))
#周长:(长加宽)x 2
#面积:长 x 宽
def chang(self):
a = (self.__chang + self.__kuan) * 2
print("周长是:",a)
def kuan(self):
i = self.__chang * self.__kuan
print("面积是:",i)
zhouchang = Ju()
zhouchang.chang()
zhouchang.kuan()
#第二种方式:
class Ju():
def __init__(self,chang,kuan):
self.long = chang #实例属性
self.width = kuan #实例属性
def zhou(self):
a = (self.long + self.width) * 2
print(f"周长是:{a}")
def mianji(self):
b = self.long * self.width
print(f"面积是:{b}")
dudu = Ju(12,34) #传入参数长和宽
dudu.zhou()
dudu.mianji()
? 注意: self
就是实例对象,通过实例对象去定义的属性都是实例属性
(1)模块
? 模块是一个包含所有你定义的函数和变量的文件,其扩展名为 .py ,模块也就是 .py 文件;模块可以被其它的程序引入,以使用该模块中的函数等功能;这也是使用Python标准库的方法
导入模块的方式:
? import 模块名
– 导入这个模块的所有功能(函数;属性;类等全部导入)
? from 模块名 import 功能名(类名;函数名等)
– 从这个模块中精准导入某一功能(类;函数等)
? from 模块名 import
? import 模块名 as 别名
– 别名为自己现取的名字(防止原文件名过长,在这个文件中临时用的名字)
? from 模块名 import 功能名 as 别名
? *注意:*在导入模块的时候不用写后面的后缀 .py ,只写文件名就可以了
? 如果在这个模块中功能过多,用import
精准导入功能名可以节省内存
#导入模块的语法格式
import 模块名
a = 模块名.类名/函数名等 #调用这个函数的某一功能
print(a)
b = 模块名.类名/函数名等 #调用这个函数的某一功能
#导入模块的语法格式
from 模块名 import 功能名(类名;函数名等)
a = 功能名
print(a)
#导入模块的语法格式
import 模块名 as bieming
a = bieming.类名/函数名等 #调用这个函数的某一功能
print(a)
b = bieming.类名/函数名等 #调用这个函数的某一功能
if __name__ == '__main__': 文件中的代码块(在初始化时不直接执行的代码)
作用:
if
判断,指定在导入文件的过程中控制去执行哪些内容(在要导入的文件内使用)? 当
__name__
的属性输出是__main__
时,说明这个代码是在当前的文件中执行的;当__name__
输出的是当前文件的文件名时,说明__name__
是在另一个文件中执行的? 被
if __name__ == '__main__':
包裹的代码块不被调用是不会初始化不自动执行的,只有被调用了才会执行
__all__ = []
作用:在
__init__.py
文件中添加__all__ = []
,控制允许导入的模块,只适用于from 包名 import 模 块名
的方式
__all__
变量的作用:控制import *
和from 包名 import *
能够导入的内容
(2)包
? 基于Python模块,在编写代码的时候,会导入许多外部代码来丰富功能;但是,如果Python的模块太多,就可能造成一定的混乱。这时候,可以通过Python包的功能来管理,包相当于一个文件夹,在该文件夹下包含了一个 __init__.py
文件,通过这个文件表示一个文件夹是Python的包,而非普通的文件夹
导入包的方式:
? import 包名.模块名
? from 包名 import 模块名
? import urllib
? 注意: urllib
就是包,按住CTRL
用鼠标左键点击urllib
,就进入了__init__.py
初始化的文件中,urllib
包中有很多的文件,如:import urllib.request
,按住CTRL
用鼠标左键点击request
,就进入了request
文件。包相当于是一个文件夹,模块就是.py文件,一个包里面可以存放多个.py文件,也就是多个模块
#导入包里面模块的语法格式
import urllib #导入包中所有的模块,如果包中模块太多可能会导致运行缓慢
import urllib.request
from urllib import request
#导入包中模块的功能的语法格式1
import urllib.request
urllib.request.Request() #Request()是功能名
#导入包中模块的功能的语法格式2
import urllib.request as R #R是别名
R.Request() #Request()是功能名
#导入包中模块的功能的语法格式3
from urllib import request
Request()
#同时在一个包中导入多个模块
from urllib import request,parse #request和parse是模块名
import request,parse
? 注意: 导入模块用import
;导入包用from
:如果只是单纯的模块就用import
;如果模块存放在包里面就用from
#导入其它路径下的.py文件
import sys
sys.path.append("绝对路径")
(1)time
模块
time
模块常用的方法:
? time.sleep(秒)
:延迟执行时间,休眠,让程序在这里暂停多长时间
? time.time()
:打印当前时间戳,单位秒
? time.localtime()
:打印本地时间以时间元组的形式输出
? time.strftime()
:接收时间元组,并返回以可读字符串表示的当地时间,格式由参数format
决定
%Y
:完整的四位数年份%y
:两位数的年份%m
:两位数的月份%d
:两位数的日期%H
:24小时制的小时数%I
:12小时制的小时数%M
:分钟数%S
:秒数(最大为60)import time
print(time.time()) #输出时间戳,以秒为单位
print(time.localtime()) #输出时间元组
print(time.sleep(3)) #运行到这里时,延迟3秒后继续往下执行
print(time.strftime('%y年 %m月 %d日', time.localtime())) #以字符串的形式输出当前时间
(2)datetime
模块
? 也是与时间相关的模块
import datetime
print(datetime.datetime.now()) #直接输出当前时间(年-月-日 时-分-秒)
(3)random
模块
? random.random()
:不用给参数,随机生成(0,1)区间的数,包含0不包含1,生成的都是小数
? random.randint()
:随机生成(x,y)区间的数,生成数包含x;y本身
? random.choice()
:从指定的序列中随机取出一个元素
? random.shuffle()
:打乱一个列表的顺序
? random.sample()
:从指定的序列中随机提取不重复的元素
import random
print(random.randint(1, 100)) #随机生成1~100的随机数,包含1和100
print(random.random()) #随机生成0~1,不包含1,生成的是小数,不需要传参数,传的话会报错
print(random.choice([12, 4, 56, 17, 78, 31])) #从这个列表中随机取出一个元素
print(random.choice(range(100))) #随机取出0~99之间的一个数
print(random.sample([4,90,56,89,54,34],2)) #有两个必备参数,缺一不可:一个是序列;一个是要随机取出多少个数,用sample取出的数不会发生重复,是唯一的
p = [45,32,57,8,43,11,50]
random.shuffle(p) #打乱列表p本身的顺序
print(p)
(4)join
模块
? json
是一个序列化的对象或数组,一种使用广泛的轻量数据格式,Python标准库中的json
模块提供了json
数据的处理功能,由于json
与Python中的字典格式非常像,所以Python中的json
模块也相当于是用来使json
与字典做转换
? 注意: 对象和数组并不是Python中的对象和数组,而是json
中的专有名词;json
中的对象对应的是Python中的字典;json
中的数组对应的是Python中的列表;序列化指的是更标准的格式,序列化的数据是可以在多个平台上使用的,如:Python中的数据是不能与JAVA;C++中的数据混用的,但json
中的数据可以;因为json
中的数据是经过序列化的,是更标准的格式,可以跨平台使用的一种格式
json
模块常用的方法:
? json.loads()
:json
转换为字典(适用于语句)
? json.dumps()
:字典转换为json
(适用于语句)
? json.load()
:json
转换为字典(适用于文件)
? json.dump()
:字典转换为json
(适用于文件)
#针对语句的示例代码
import json
A = {"age":18} #字典格式
B = '{"age":18}' #json格式;属于字符串类型
print(type(B))
#把json格式的B转换成字典,通过json进行语句转换
#不能使用str进行强制转换,因为字典可以转换成其它的序列,但是其它的序列不能直接转换成字典;字典与字典可以互转
a = json.loads(B)
print(a,type(a))
#把字典A转换为json格式(str类型),通过json进行语句转换
b = json.dumps(A)
print(b,type(b))
C = {"name":"张四"}
print(json.dumps(C)) #此时因为字典中有中文,json格式会把中文变成ASCII编码
print(json.dumps(C,ensure_ascii=False)) #此时中文便被固定住了,不会进行ASCII编码转换
#针对文件的示例代码
name = {"name":"张四"}
import json
with open('json.txt','w',encoding='utf-8') as i:
json.dump(name,i,ensure_ascii=False)
with open('json.txt','r',encoding='utf-8') as i:
a = json.load(i)
print(a)
? 注意: json是一种通用格式,是跨编程语言的工具
? 当检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的异常
? 异常是一个事件,该事件会在程序执行过程中发生,影响程序的正常执行,当Python脚本发生异常时我们可以捕获并处理它,不然程序会终止执行;当对异常进行捕获之后,它就不会影响整体程序的执行。只要是报错,它就是一个异常
#语法1
try: #这一句在异常语法里是必须要有的
程序正常执行的代码
except: #捕获异常
抛出错误时执行此代码块
#语法2
try:
程序正常执行的代码
except Exception as a:
抛出错误时执行此代码块
else: #检验代码的正确性
程序没有抛出错误时执行此代码块
finally:
不管程序有无异常,都会执行的代码块
#示例代码
a = "w"
try:
b = int(a) #try里面的代码无论如何都会执行
except:
print("这句代码有错误") #except里面的代码是当try里面的代码出现异常时执行
else:
print("代码正确") #else里面的代码是当try里面的代码没有异常出现时执行
finally:
print("我就是路过") #try里面的代码无论是否出现异常都会执行
print("dudu")
#输入一个数字并加上10
try:
num = int(input("请输入数字:"))
except:
num = 1
print("输入有误,已经强制为num赋值为1")
print(num+10)
? 注意: else
和finally
是可以省略不写的
异常名称 | 描述 |
---|---|
AttributeError | 对象没有这个属性 |
OSError | 操作系统错误 |
ImportError | 导入模块/对象失败 |
IndexError | 序列中没有此索引(index ) |
KeyError | 没有这个键 |
NameError | 未声明/初始化对象(没有属性) |
SyntaxError | Python语法错误 |
TypeError | 对类型无效的操作 |
ValueError | 传入无效的参数 |
Warning | 警告的基类 |
? 注意:Warning
是警告,警告一般都不会影响程序的执行
? 在实际开发中,在程序不满足某条件时,通常会主动抛出异常,语法如下:
raise Exception()
? 注意:raise
关键字表示自动触发异常,就算代码没有错误,也让它报错
#判断烧饼熟了没,当烹饪时间小于5小时,主动触发没熟异常
def cooking(minutes):
if minutes < 5:
raise Exception(f'{minutes}分钟没熟,不能吃') #手动的去触发异常
else:
print("熟了,放心吃")
cooking(6)
%Y
:完整的四位数年份%y
:两位数的年份%m
:两位数的月份%d
:两位数的日期%H
:24小时制的小时数%I
:12小时制的小时数%M
:分钟数%S
:秒数(最大为60)import time
print(time.time()) #输出时间戳,以秒为单位
print(time.localtime()) #输出时间元组
print(time.sleep(3)) #运行到这里时,延迟3秒后继续往下执行
print(time.strftime('%y年 %m月 %d日', time.localtime())) #以字符串的形式输出当前时间
(2)datetime
模块
? 也是与时间相关的模块
import datetime
print(datetime.datetime.now()) #直接输出当前时间(年-月-日 时-分-秒)
(3)random
模块
? random.random()
:不用给参数,随机生成(0,1)区间的数,包含0不包含1,生成的都是小数
? random.randint()
:随机生成(x,y)区间的数,生成数包含x;y本身
? random.choice()
:从指定的序列中随机取出一个元素
? random.shuffle()
:打乱一个列表的顺序
? random.sample()
:从指定的序列中随机提取不重复的元素
import random
print(random.randint(1, 100)) #随机生成1~100的随机数,包含1和100
print(random.random()) #随机生成0~1,不包含1,生成的是小数,不需要传参数,传的话会报错
print(random.choice([12, 4, 56, 17, 78, 31])) #从这个列表中随机取出一个元素
print(random.choice(range(100))) #随机取出0~99之间的一个数
print(random.sample([4,90,56,89,54,34],2)) #有两个必备参数,缺一不可:一个是序列;一个是要随机取出多少个数,用sample取出的数不会发生重复,是唯一的
p = [45,32,57,8,43,11,50]
random.shuffle(p) #打乱列表p本身的顺序
print(p)
(4)join
模块
? json
是一个序列化的对象或数组,一种使用广泛的轻量数据格式,Python标准库中的json
模块提供了json
数据的处理功能,由于json
与Python中的字典格式非常像,所以Python中的json
模块也相当于是用来使json
与字典做转换
? 注意: 对象和数组并不是Python中的对象和数组,而是json
中的专有名词;json
中的对象对应的是Python中的字典;json
中的数组对应的是Python中的列表;序列化指的是更标准的格式,序列化的数据是可以在多个平台上使用的,如:Python中的数据是不能与JAVA;C++中的数据混用的,但json
中的数据可以;因为json
中的数据是经过序列化的,是更标准的格式,可以跨平台使用的一种格式
json
模块常用的方法:
? json.loads()
:json
转换为字典(适用于语句)
? json.dumps()
:字典转换为json
(适用于语句)
? json.load()
:json
转换为字典(适用于文件)
? json.dump()
:字典转换为json
(适用于文件)
#针对语句的示例代码
import json
A = {"age":18} #字典格式
B = '{"age":18}' #json格式;属于字符串类型
print(type(B))
#把json格式的B转换成字典,通过json进行语句转换
#不能使用str进行强制转换,因为字典可以转换成其它的序列,但是其它的序列不能直接转换成字典;字典与字典可以互转
a = json.loads(B)
print(a,type(a))
#把字典A转换为json格式(str类型),通过json进行语句转换
b = json.dumps(A)
print(b,type(b))
C = {"name":"张四"}
print(json.dumps(C)) #此时因为字典中有中文,json格式会把中文变成ASCII编码
print(json.dumps(C,ensure_ascii=False)) #此时中文便被固定住了,不会进行ASCII编码转换
#针对文件的示例代码
name = {"name":"张四"}
import json
with open('json.txt','w',encoding='utf-8') as i:
json.dump(name,i,ensure_ascii=False)
with open('json.txt','r',encoding='utf-8') as i:
a = json.load(i)
print(a)
? 注意: json是一种通用格式,是跨编程语言的工具
? 当检测到一个错误时,解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的异常
? 异常是一个事件,该事件会在程序执行过程中发生,影响程序的正常执行,当Python脚本发生异常时我们可以捕获并处理它,不然程序会终止执行;当对异常进行捕获之后,它就不会影响整体程序的执行。只要是报错,它就是一个异常
#语法1
try: #这一句在异常语法里是必须要有的
程序正常执行的代码
except: #捕获异常
抛出错误时执行此代码块
#语法2
try:
程序正常执行的代码
except Exception as a:
抛出错误时执行此代码块
else: #检验代码的正确性
程序没有抛出错误时执行此代码块
finally:
不管程序有无异常,都会执行的代码块
#示例代码
a = "w"
try:
b = int(a) #try里面的代码无论如何都会执行
except:
print("这句代码有错误") #except里面的代码是当try里面的代码出现异常时执行
else:
print("代码正确") #else里面的代码是当try里面的代码没有异常出现时执行
finally:
print("我就是路过") #try里面的代码无论是否出现异常都会执行
print("dudu")
#输入一个数字并加上10
try:
num = int(input("请输入数字:"))
except:
num = 1
print("输入有误,已经强制为num赋值为1")
print(num+10)
? 注意: else
和finally
是可以省略不写的
异常名称 | 描述 |
---|---|
AttributeError | 对象没有这个属性 |
OSError | 操作系统错误 |
ImportError | 导入模块/对象失败 |
IndexError | 序列中没有此索引(index ) |
KeyError | 没有这个键 |
NameError | 未声明/初始化对象(没有属性) |
SyntaxError | Python语法错误 |
TypeError | 对类型无效的操作 |
ValueError | 传入无效的参数 |
Warning | 警告的基类 |
? 注意:Warning
是警告,警告一般都不会影响程序的执行
? 在实际开发中,在程序不满足某条件时,通常会主动抛出异常,语法如下:
raise Exception()
? 注意:raise
关键字表示自动触发异常,就算代码没有错误,也让它报错
#判断烧饼熟了没,当烹饪时间小于5小时,主动触发没熟异常
def cooking(minutes):
if minutes < 5:
raise Exception(f'{minutes}分钟没熟,不能吃') #手动的去触发异常
else:
print("熟了,放心吃")
cooking(6)