可以使用type() 查看变量类型 通过type(变量)是查看变量的类型还是数据的类型???
变量存储的数据类型,因为变量无类型,但是存储的数据有
数据类型之间,在特定的场景下,是可以相互转换的,如字符串转数字,数字转字符串等。
为什么要转换类型:
常见的转成语句
语句(函数) | 说明 |
---|---|
int(x) | 将x转成一个整型 |
float(x) | 将x转成一个浮点型 |
str(x) | 将对象x转成字符串 |
注意:这三个语句,都是带有结果的(返回值)我们可以用print直接输出,或者用变量存储结果值。
# 将数字变成字符串
num_str = str(11)
print(type(num_str), num_str) # 结果 11
# 浮点数转字符串
float_str = str(11.11)
print(type(flost_str), flost_str) # 结果 11.11
# 将字符串转成数字
num = int("11")
print(type(num), num) # 结果 11
注意:int("[字符或者中文]") int("11.11") 将会报错 [ValueError: invalid literal for int() with xxxx]
# 将字符串转成float
num_float = float("11.11")
print(type(num_float), num_float) # 结果 11.11
注意:float("11") 将输入 11.0
# 整数转浮点数
float_num = float("11")
输出11.0
# 浮点数转整型(会丢失精度)
int_num = int(11.11)
输入 11
这些名字,统一称之为标识符,用来做内容的标识;
python,标识符命名规则:
变量命名规范
算术运算符
运算符 | 描述 | 实例 |
---|---|---|
+ | 加 | 两个对象相加 |
- | 减 | 得到负数,或是一个数减去另一个数 |
* | 乘 | 两个数相乘或是返回被重复诺干次的字符串a*b输出结果 |
/ | 除 | 两个数相除 |
// | 取整除 | 返回商的整数部分 |
% | 取余 | 返回除法的余数 |
** | 指数 | a**b为10的20次方 |
赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
= | 赋值运算符 | 把=号右边的结果赋值给=左边的变量 |
复合赋值运算符
运算符 | 描述 | 实例 |
---|---|---|
+= | 加法赋值运算符 | c += a c = c + a |
-= | 减法赋值运算符 | c -= a c = c - a |
*= | 乘法赋值运算符 | c *= a c = c * a |
/= | 除法赋值运算符 | c /= a c = c / a |
%= | 取模赋值运算符 | c %= a c = c % a |
**= | 幂赋值运算符 | c **= a c = c ** a |
//= | 取整除赋值运算符 | c //= a c = c // a |
num = 10
class_num = 10
message = "年段第%s班级,共有%s人" % (num, class_num)
"""
其中 %s表示将变量变成字符串放入占位的地方(这里将数字变成字符串放入)
% 表示: 我要占位
注意: 多个变量占位,变量要用括号括起来,并按照占位的顺序引入
python 支持多种数据类型占位
1. %s 转成字符串
2. %d 转成整数
3. %f 转成浮点数
"""
实例:
%5d: 表示将整数的宽度控制在5位,如数字11,被设置为5d,就会变成 [空格][空格][空格]11, 用三个空格补足宽度
%5.2f, 表示将宽度控制在5,将小数点精度设置为2。小数点和小数部分也算入宽度计算,如对11.345设置了%7.2f后,结果是 :[空格][空格]11.35, 2个空格补足宽度,小数点部分限制2位精度,四舍五入为.35
%.2f: 表示不限制宽度,只设置小数点精度为2,如11.345设置后为11.35
name = "xxxx"
stock_price = 11.11
stock_code = 100000
stock_price_daily_factor = 1.2
growth_days = 7
print(f"公司{name}, 股票代码:{stock_code} 当前股价:{stock_price}")
print("每日增长系数:%.2f, 经过%d天, 股价变成了%.2f" % (
stock_price_daily_factor, growth_days, stock_price * stock_price_daily_factor ** growth_days))
input 语句(函数) 用来获取键盘输入
数据输出:print
数据输入: input
使用方法:
使用input()语句可以从键盘上获取输入
使用一个变量接受存储input语句获取的键盘输入数据即可
代码:
print("输入名字:")
name = input() # 回车结束输入
print(name)
name = input("输入名字:")
print(name)
布尔类型不仅可以自定定义,也可以通过计算的来,也就是使用比较运算符进行运算得到的布尔类型的结果
运算符 | 描述 | 示例 |
---|---|---|
== | 判断内容是否相等,满足True,不满足False | a = 3 b = 3 a == b为True |
!= | 判断内容是否不相等 | a = 1 b = 3 a != b True |
> | ||
< | ||
>= | ||
<= |
if 要判断的条件:
条件成立,要做的事情
例子代码:
if age >= 18:
print("已经成年")
判断语句的结果,必须是布尔类型True或者False
True会执行if内的代码语句
False则不会执行
age = int(input("你的年纪:"))
if age >= 18:
print("你已经成年,门票30")
if age < 18:
print("你未成年,门票10")
if 条件:
满足 TODO
else:
不满足 TODO
例子:
age = int(input("你的年纪:"))
if age >= 18:
print("你已经成年,门票30")
else:
print("你未成年,门票10")
if 条件1:
满足条件1 TODO
elif 条件2:
满足条件2 TODO
elif 条件3:
满足条件3 TODO
else:
都不满足 TODO
例子:
age = int(input("你的年纪:"))
if age > 60:
print("大于60岁免费")
elif age >= 18:
print("你已经成年,门票30")
else:
print("你未成年,门票10")
注意:判断是互斥且有顺序的
if 条件1:
满足条件1 TODO
if 条件2:
满足条件2, TODO
第二个if 属于第一个if内,只有第一个if满足条件,才会执行第二个if
嵌套的关键点,在于:空格缩进
通过空格缩进,来决定语句之间的层次关系
import random
num = random.randint(1, 10) # 随机数 1到10以内的整型随机数
guess_num = int(input("输入你要猜测的数字"))
if guess_num == num:
print("恭喜你,猜中了")
else:
if guess_num > num:
print("大了")
else:
print("小了")
guess_num = int(input("输入你要猜测的数字"))
if guess_num == num:
print("恭喜你,猜中了")
else:
if guess_num > num:
print("大了")
else:
print("小了")
guess_num = int(input("输入你要猜测的数字"))
if guess_num == num:
print("恭喜你,猜中了")
else:
if guess_num > num:
print(f"大了, 游戏结束,数字为:{num}")
else:
print(f"小了,游戏结束,数字为:{num}")
while 条件:
条件满足 TODO
....
直到条件不满足则退出循环
### 注意: 只要条件一直满足,会无限循环执行,造成死循环
例子:
i = 0
while i < 100:
print(i)
i += 1
# 循环输出0-99,直到i = 100 不满足i < 100 退出循环
例子:求1-100的和
i = 1
num_sum = 0
while i <= 100:
num_sum += i
i += 1
print(num_sum)
注意:
猜数字使用while改进:
import random
num = random.randint(1, 10) # 随机数 1到10以内的整型随机数
count = 1
flag = True
while flag:
guess_num = int(input("输入你要猜测的数字"))
if guess_num == num:
print(f"恭喜你,猜中了用猜了{count}次")
flag = False
else:
if guess_num > num:
print("大了,继续")
else:
print("小了, 继续")
count += 1
while 条件1:
条件满足 TODO
....
while 条件2:
满足条件2 TODO
....
直到条件2不满足则退出循环
直到条件1不满足则退出循环
注意:
补充知识:
1. print输出不换行 在print语句中加入 end="" 即输出不换行
2. 制表符 \t 效果等于在键盘上按下tab键 可以让多行字符串进行对齐
案例: 九九乘法表
i = 1
while i <= 9:
j = 1
while j <= i:
print(f"{j} * {i} = {i * j}\t", end="")
j += 1
i += 1
print()
除while循环外。python支持for循环语句
区别:
语法:
for 临时变量 in 待处理数据集:
循环满足条件时执行的代码
语法中:待处理数据集,称之为:序列类型
序列类型值:其内容可以一个个依次取出来的一种类型,包括:
range语句:获得一个简单的数字序列
变量作用域:
语法
例子:遍历字符串
name = "ccyylllc"
for x in name:
print(x)
# for 循环将字符串的内容依次取出,for循环也被称为:遍历循环
例子: 计算a出现的次数
count = 0
str = "xasasasagagsdga"
for s in str:
if s == 'a':
count += 1
print(count)
例子: 1 - 100 (不包含100) 有几个偶数
count = 0
for i in range(1, 100):
if i % 2 == 0:
count += 1
print(count)
注意:
语法:
for 临时变量1 in 待处理数据集:
满足循环条件的TODO
…
for 临时变量2 in 待处理数据集:
满足循环条件的TODO
注意事项:
for i in range(1, 10):
j = i
for j in range(1, i+1):
print(f"{j} * {i} = {i * j}\t", end="")
print()
continue:
break:
在嵌套循环中,只能作用在所在循环上,无法对上层循环起作用
import random
all_price = 10000
person_num = 20
i = 1
while i <= 20:
score = random.randint(1, 10)
if score < 5:
print(f"第{i}号员工,绩效{score}低于5分,不发工资")
else:
if all_price == 0:
print("工资发完了,下个月再说")
break
all_price -= 1000
print(f"第{i}号员工,绩效{score},发工资1000,公司余额:{all_price}")
i += 1
是组织好的,可重复使用,用来实现特定功能的代码段
为什么要使用函数:
语法:
def 函数名(传入参数):
函数体
return 返回值
调用:
函数名(参数)
def check(x):
if x >= 37.5:
print("你已经发烧,需要隔离")
else:
print("体温正常")
check(37.7)
定义:函数在执行完成后,返回给调用者的结果
返回值的应用语法:
注意:
None类型:
如果没有使用return语句返回数据,那么函数有返回值吗?
有的,Python中有一个特色的字面量,None,其类型是:
无返回值的函数,实际上就是返回了None这个字面量
None表示 空的,无实际意义
函数返回的None 就标识,这个函数没有返回什么有意义的内容,也就是返回了空的意思
应用场景:
def check(x):
"""
返回判断结果
:param x:
:return:
"""
if x >= 37.5:
print("你已经发烧,需要隔离")
else:
print("体温正常")
# 快捷注释:在函数名称下面输入6个引号后在中间回车
指:一个函数里面又调用了另外一个函数
执行流程:
num = 200
def change_num1():
num = 100
def change_num2():
global num
num = 300
change_num1()
print(num) # 结果 200 因为change_num1 赋值的num的局部变量
change_num2()
print(num) #结果 300 使用global声明变量为全局变量
money = 20000
name = "xxxx"
def init():
print("-----------主菜单-----------")
print("查询余额 1")
print("存款 2")
print("取款 3")
print("退出 4")
return int(input("请输入你的选择:"))
def search():
print("----------查询余额-----------")
print(f"{name}的剩余金额:{money}")
def getOrSet(use_money, flag):
global money
if flag == 1:
money += use_money
else:
money -= use_money
print(f"你的{'存款' if flag == 1 else '取款'}操作成功,现在余额{money}")
def close():
print("退出成功")
if __name__ == '__main__':
while True:
ops = init()
if ops == 1:
search()
elif ops == 2:
getOrSet(200, 1)
elif ops == 3:
getOrSet(400, 2)
elif ops == 4:
close()
break
else:
print("输入错误,请重新输入")
continue
定义:
一种可以容纳多份数据的数据类型,容纳的每一份数据称之为1个元素,每一个元素,可以是任意类型的数据,如字符串,数字,布尔等
特点:
分为5类:
# 字面量
[元素1, 元素2, 元素3, 元素4, ...]
# 定义元素
变量名称 = [元素1, 元素2, 元素3, 元素4, ...]
# 定义空列表
变量名称 = []
变量名称 = list()
注意:列表可以一次存储多个数据,且可以为不同的数据类型,支持嵌套
列表的查询功能(方法)
列表的修改功能(方法)
特点:
my_list = ["demo1", "demo2", "demo3", "demo4"]
print(my_list.index("demo1")) # 0
print(my_list.index("demo0")) # ValueError: 'demo0' is not in list
my_list[0] = "demo0"
my_list[-1] = "demo-1"
my_list[4] = "demo4" # IndexError: list assignment index out of range
print(my_list[0]) # demo0
print(my_list[-1]) # demo-1
print(my_list[4])
list_len = len(my_list)
print(list_len) # 4
my_list.insert(3, "demo5")
print(my_list) # ['demo1', 'demo2', 'demo3', 'demo5', 'demo4']
my_list.append("demo6")
print(my_list) # ['demo1', 'demo2', 'demo3', 'demo5', 'demo4', 'demo6']
my_list.extend(["demo7", "demo8", "demo10"])
print(my_list) # ['demo1', 'demo2', 'demo3', 'demo5', 'demo4', 'demo6', 'demo7', 'demo8', 'demo10']
del my_list[8]
print(my_list) # ['demo1', 'demo2', 'demo3', 'demo5', 'demo4', 'demo6', 'demo7', 'demo8']
del_str = my_list.pop(7)
print(my_list, del_str) # ['demo1', 'demo2', 'demo3', 'demo5', 'demo4', 'demo6', 'demo7'] demo8
my_list.remove("demo2")
print(my_list) # ['demo1', 'demo3', 'demo5', 'demo4', 'demo6', 'demo7']
num = my_list.count("demo1")
print(num) # 1
my_list.clear()
print(my_list) # []
"""
有一个列表,内容是[21, 25, 21, 23, 22, 20], 记录一批学生年纪
"""
# 定义一个列表,并用变量接受它
my_list = [21, 25, 21, 23, 22, 20]
# 追加一个数字31到列表微博
my_list.append(31)
print(my_list) # [21, 25, 21, 23, 22, 20, 31]
# 追加一个新列表[29, 33, 30] 到尾部
my_list.extend([29, 33, 30])
print(my_list) # [21, 25, 21, 23, 22, 20, 31, 29, 33, 30]
# 取出第一个元素 [21]
num1 = my_list.pop(0)
print(num1) # 21
# 取出最后一个元素
num2 = my_list.pop(len(my_list) - 1)
print(num2) # 30
# 查找元素31,在列表中下标位置
print(my_list.index(31)) # 5
使用while
index = 0
while index < len(list):
print(list[index])
index += 1
使用for循环
for 临时变量 in 数据容器
对临时变量进行处理
for element in list:
print(element)
while循环和for循环,都是循环语句,但是细节不同
为什么需要元组:如果想要传递的信息,不被篡改,列表就不合适
元组用列表一样,都是可以封装多个,不同类型的元素在内。
但是最大的不同点在于:
元组一旦定义完成,就不可修改
所以当我们需要在程序内封装数据,又不希望封装的数据被篡改,那么元组就非常合适
定义元组:
定义元组使用小括号,且使用逗号合开各个数据,数据可以是不同的数据类型
# 定义元组字面量
(元素, 元素, .... , 元素)
# 定义元组变量
变量名称 = (元素, 元素, .... , 元素)
# 定义空元组
变量名称 = ()
变量名称 = tuple()
注意:元组只有一个数据,这个数据后面要添加逗号
t1 = ((1, 2, 3), (4, 5, 6))
# 通过下标索引取出数据 6
num = t1[1][2]
元组的相关操作:
# 元组遍历
# while遍历
index = 0
while index < len(元组):
print(元组[index])
index += 1
# for遍历
for item in 元组:
print(item)
元组特点:
元组注意事项:
字符串是字符的容器,一个字符串可以存放任意数量的字符
字符串的下标(索引)
和其他容器一样,列表,元组一样,字符串也可以通过下标来进行访问
同元组一样,字符串是一个:无法修改的数据容器
如果必须要修改,只能得到新的字符串,老字符串无法修改
字符串常用的操作
my_str = " iitemasdadfad badfa "
my_str2 = "12iitemasdadfad badfa21"
# index 方法
print(my_str.index("ad")) # 8
# replace方法
print(my_str.replace("ad", ",,")) # iitemasd,,f,, b,,fa
# split方法
print(my_str.split("a")) # ['iitem', 'sd', 'df', 'd b', 'df', ' ']
print(my_str.split("a", 2)) # ['iitem', 'sd', 'dfad badfa ']
# strip方法
print(my_str.strip()) # iitemasdadfad badfa
print(my_str2.strip("12")) # iitemasdadfad badfa
# 注意:传入的是12,其实是"1"和"2" 都会被移除,是按照单个字符
# 统计字符串中某字符串出现的次数
print(my_str.count("ab")) # 0
# 统计字符串的长度
print(len(my_str)) # 21
序列是指:内容连续,有序,可使用下标索引的一类数据容器
列表,元组,字符串,均可以视为序列
序列支持切片,即列表,元组,字符串支持进行切片操作,
切片:从一个序列中,取出一个子序列
语法:序列[起始下标: 结束下标: 步长]
表示从序列中,从指定位置开始,依次取出元素,到指定位置结束,得到一个新序列
# 对list进行切片,从1开始,4结束,步长1
my_list = [0, 1, 2, 3, 4, 5, 6]
print(my_list[1:4]) # 步长1可以默认不写 [1, 2, 3]
# 对tuple进行切片,从头开始,到最后结束,步长1
my_tuple = (0, 1, 2, 3, 4, 5, 6)
print(my_tuple[:]) # 起始和结束不写表示从头到尾,步长为1省略 (0, 1, 2, 3, 4, 5, 6)
# 对str进行切片,从头开始,到最后结束,步长2
my_str = "01234567"
print(my_str[::2]) # 0246
# 对str进行切片,从头开始,到最后结束,步长-1
my_str2 = "01234567"
print(my_str2[::-1]) # 等同于将序列反转 76543210
# 对列表进行切片,从3开始,到1 结束,步长-1
my_list2 = [0, 1, 2, 3, 4, 5, 6]
print(my_list2[3:1:-1]) # [3, 2]
# 对元组进行切片,从头开始,到尾结束,步长-2
my_tuple2 = (0, 1, 2, 3, 4, 5, 6)
print(my_tuple2[::-2]) # (6, 4, 2, 0)
语法:
# 定义集合字面量
{元素, 元素, 元素, ..., 元素}
# 定义集合变量
变量名称 = {元素, 元素, 元素, ..., 元素}
# 定义空集合
变量名称 = set()
集合的操作:(因为集合是无序的,所以集合不支持:下标索引)但是和列表一样是允许修改的
my_set = {"demo1", "demo2", "demo3", "demo4"}
# 添加新元素
my_set.add("demo5")
print(my_set) # {'demo3', 'demo4', 'demo1', 'demo5', 'demo2'} 输出没按照顺序,因为他是无序的
# 移除新元素
my_set.remove("demo5")
print(my_set) # {'demo3', 'demo4', 'demo1', 'demo2'}
# 随机去除一个元素
str = my_set.pop()
print(str) # demo3
# 清空集合
my_set.clear()
print(my_set) # set()
# 取出两个集合的差集
set1 = {1, 2, 3, 4}
set2 = {3, 4, 7, 8}
set3 = set1.difference(set2)
print(set1) # {1, 2, 3, 4}
print(set2) # {8, 3, 4, 7}
print(set3) # {1, 2}
# 消除两个集合的差集
set1 = {1, 2, 3, 4}
set2 = {3, 4, 7, 8}
set3 = set1.difference_update(set2)
print(set1) # {1, 2}
print(set2) # {{8, 3, 4, 7}
print(set3) # None
# 2个集合合并为1个
set1 = {1, 2, 3, 4}
set2 = {3, 4, 7, 8}
set3 = set1.union(set2)
print(set1) # {1, 2, 3, 4}
print(set2) # {8, 3, 4, 7}
print(set3) # {1, 2, 3, 4, 7, 8}
# 统计集合元素的数量
set1 = {1, 2, 3, 4}
print(len(set1)) # 4
# 集合遍历
set1 = {1, 2, 3, 4}
for item in set1:
print(item)
特点:
定义:同样使用{},不过存储的元素是一个个的:
# 定义字典字面量
{key: value, key: value, key: value, ..., key: value}
# 定义字典变量
my_dict = {key: value, key: value, key: value, ..., key: value}
# 定义空字典
my_dict = {}
my_dict = dict()
数据的获取:
注意事项:
字典常用超出:
my_dict = {"demo1": 1, "demo2": 2, "demo3": 3}
# 新增元素
my_dict["demo4"] = 4
print(my_dict) # {'demo1': 1, 'demo2': 2, 'demo3': 3, 'demo4': 4}
# 更新元素
my_dict["demo3"] = 33
print(my_dict) # {'demo1': 1, 'demo2': 2, 'demo3': 33, 'demo4': 4}
# 删除元素
my_dict.pop("demo3")
print(my_dict) # {'demo1': 1, 'demo2': 2, 'demo4': 4}
# 清空元素
my_dict.clear()
print(my_dict) # {}
# 获取全部的key
my_dict = {"demo1": 1, "demo2": 2, "demo3": 3}
print(my_dict.keys()) # dict_keys(['demo1', 'demo2', 'demo3'])
# 遍历字典
for item in my_dict.keys():
print(item, end="") # dict_keys(['demo1', 'demo2', 'demo3'])
print(my_dict[item], end="") # demo11demo22demo33
# 统计字典内的元素数量
my_dict = {"demo1": 1, "demo2": 2, "demo3": 3}
print(len(my_dict)) # 3
my_list = [1, 2, 3, 4, 5]
my_tuple = (1, 2, 3, 4, 5)
my_Str = "adbadfgh"
my_dict = {"key1": 1, "key2": 2, "key3": 3}
my_set = {1, 2, 3, 4, 5}
# len 元素个数
print(len(my_list)) # 5
print(len(my_tuple)) # 5
print(len(my_Str)) # 8
print(len(my_dict)) # 3
print(len(my_set)) # 5
# max最大元素
print(max(my_list)) # 5
print(max(my_tuple)) # 5
print(max(my_Str)) # h
print(max(my_dict)) # key3
print(max(my_set)) # 5
# min最小元素
print(min(my_list)) # 1
print(min(my_tuple)) # 1
print(min(my_Str)) # a
print(min(my_dict)) # key1
print(min(my_set)) # 1
# 类型转换: 容器转列表
print(list(my_list)) # [1, 2, 3, 4, 5]
print(list(my_Str)) # ['a', 'd', 'b', 'a', 'd', 'f', 'g', 'h']
print(list(my_tuple)) # [1, 2, 3, 4, 5]
print(list(my_set)) # [1, 2, 3, 4, 5]
print(list(my_dict)) # ['key1', 'key2', 'key3']
# 容器转元组
print(tuple(my_list)) # (1, 2, 3, 4, 5)
print(tuple(my_Str)) # ('a', 'd', 'b', 'a', 'd', 'f', 'g', 'h')
print(tuple(my_tuple)) # (1, 2, 3, 4, 5)
print(tuple(my_set)) # (1, 2, 3, 4, 5)
print(tuple(my_dict)) # ('key1', 'key2', 'key3')
# 容器转集合
print(set(my_list)) # {1, 2, 3, 4, 5}
print(set(my_Str)) # {'g', 'd', 'f', 'h', 'b', 'a'}
print(set(my_tuple)) # {1, 2, 3, 4, 5}
print(set(my_set)) # {1, 2, 3, 4, 5}
print(set(my_dict)) # {'key1', 'key2', 'key3'}
# 容器转字符串
print(str(my_list)) # [1, 2, 3, 4, 5]
print(str(my_Str)) # adbadfgh
print(str(my_tuple)) # (1, 2, 3, 4, 5)
print(str(my_set)) # {1, 2, 3, 4, 5}
print(str(my_dict)) # {'key1': 1, 'key2': 2, 'key3': 3}
示例:
def test_return():
return 1, 2
x, y = test_return
按照返回值的顺序,写对应顺序的多个变量接收即可,变量之间用逗号隔开,支持不同类型的数据return
使用方式上的不同,函数有4中常见参数使用方式
def user_info(name, age, gender):
TODO
user_info("name", "age", "gender")
# 注意: 传递的参数和定义的参数的顺序及个数必须一致
# 关键字参数:函数调用时通过“键=值”形式传递参数
# 作用:可以让函数更加清晰,容易使用,同时也消除了参数的顺序
def user_info(name, age, gender)
TODO
# 关键字传参
user_info(name = "name", age = "age", gender = "gender")
# 可以不按照固定顺序
user_info(age = "age", gender = "gender", name = "name")
# 可以和位置参数混用,位置参数必须在前面,且匹配参数顺序
user_info("name", age = "age", gender = "gender")
# 注意:函数调用时,如果有位置参数时,位置参数必须在关键字参数前面,但关键字参数之间不存在先后顺序
"""
缺省参数也叫默认参数,用于定义函数,为参数提供默认值,调用函数是可不传该默认参数的值(注意: 所有位置参数必须出现在默认参数前,包括函数的定义和调用)
作用: 当调用函数时没有传递参数,就会使用默认是用缺省参数对应的值
"""
def user_info(name, age, gender = "男")
TODO
user_info("name", "age")
user_info("name", "age", "gender")
注意:
函数调用时,如果为缺省参数传递则修改默认值,否则使用这个默认值
"""
不定长参数也叫可变参数,用于不确定调用的时候,会传递多少个参数(不传参也可以)的场景
作用: 当调用函数时不确定参数的个数时,可以使用不定长参数
不定长参数的类型:
1.位置传递
2.关键字传递
"""
# 位置传递
def user_info(*args):
TODO
user_info("name")
user_info("name","age")
注意:传进的所有参数都会被args变量收集,它会根据传进参数的位置合并成一个元组,args是元组类型,这就是位置传递
# 关键字传递
def user_info(**kwargs):
TODO
user_info(name = "name", age = "age")
# 注意:参数是“键值对”形式的情况下,都会被keyWords接收,同时会根据"键值对"组成字典
函数作为参数传递
def test_func(compute):
result = compute(1, 2)
TODO
def compute(x, y):
TODO
test_func(compute)
"""
函数compute,作为参数,传入了test_func函数中使用
test_func需要一个函数作为参数传入,这个函数需要接受两个数字进行计算,计算逻辑由这个被传入函数决定
compute函数接受2个数字对其进行计算,compute函数作为参数,传递给了test_func函数使用
最终,在test_func函数内部,由传入的compute函数,完成对数字的计算操作
这是一种计算逻辑的传递,而非数据的传递
任何逻辑都可以自定定义并作为函数传入
"""
lambda匿名函数:
函数定义中:
有名称的函数,可以基于名称重复使用
无名称的匿名函数,只可临时使用一次
匿名函数定义语法:
lambda 传入参数: 函数体(一行代码)
def test_func(compute):
result = compute(1, 2)
print(result)
test_func(lambda x, y: x + y)
在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新的文件
open(name, mode, encoding)
name: 要打开的目标文件名的字符串,可以包含文件所在的具体路径
mode: 设置打开文件的模式(访问模式):只读,写入, 追加等等
encoding:编码格式
实例代码:
f = open("text.txt","r",encoding="utf-8")
注意:encoding的顺序不是第三位,所以不能用位置参数,用关键字参数直接指定、
注意事项:此时的‘f’是‘open’函数的文件对象,
############################################################
mode 常用的三种基础访问模式
r: 以只读方式打开文件,文件的指针将会放在文件的开头,这是默认方式
w: 打开一个文件只用于写入,如果该文件已存在则打开文件,并从开头开始编辑,原有内容会被删除,如果该文件不存在,创建新文件
a: 打开一个文件用于追加,如果该文件写存在,新的内容将会写入到已有的内容之后,如果该文件不存在,创建新文件进行写入
读取相关操作
"""
在python,使用open函数,可以打开一个已经存在的文件,或者创建一个新的文件
open(name, mode, encoding)
name: 要打开的目标文件名的字符串,可以包含文件所在的具体路径
mode: 设置打开文件的模式(访问模式):只读,写入, 追加等等
encoding:编码格式
实例代码:
f = open("text.txt","r",encoding="utf-8")
注意:encoding的顺序不是第三位,所以不能用位置参数,用关键字参数直接指定、
注意事项:此时的‘f’是‘open’函数的文件对象,
"""
# 打开文件
f = open("D:/Desktop/test.txt", "r", encoding="utf-8")
print(type(f)) #
# 读取文件 --- read()
print("f 读取10个字节的结果", f.read(10)) # f 读取10个字节的结果 1111111111
print("f 读取全部的结果", f.read()) # 文件全部数据
f.close()
# 读取文件 readlines()
f = open("D:/Desktop/test.txt", "r", encoding="utf-8")
lines = f.readlines()
print(type(lines)) #
print(lines) # ['11111111111111111111111\n', '22222222222222222222222\n', '333333333333333333333333\n',
# '44444444444444444444444444\n', '55555555555555555555555555\n', '6666666666666666666666666666\n',
# '77777777777777777777777777777\n', '8888888888888888888888888888888\n', '9999999999999999999999999999999999\n',
# '101010101010101010101010101010101010\n', '11111111111111111111111111111111111111111']
f.close()
# 读取文件 readline() 一次读取一行
f = open("D:/Desktop/test.txt", "r", encoding="utf-8")
line = f.readline()
print(type(line)) #
print(line) # 11111111111111111111111
f.close()
count = 0
with open("D:/Desktop/test.txt", "r", encoding="utf-8") as f:
for item in f.readlines():
count += item.count("111")
print(count) # 20
写入快速入门:
案例演示:
# 打开文件
f = open("py.txt", "w")
# 文件写入
f.write("hello, word")
# 内容刷新
f.flush()
## 注意:
1. 直接调用write,内容并为真正写入文件,而是会积攒在程序的内存里,称之为缓冲区
2. 当调用flush的时候,内容会真正写入文件
3. 这样做的避免频繁的操作硬盘,导致效率下降(赞一堆,一次性写磁盘)
写入文件使用open函数“w”模式进行写入
写入的方法有:
注意实现:
案例演示:
# 1 打开文件,通过a模式打开即可
f = open("文件", "a")
# 2. 文件写入
f.write("hello world)
#3. 内容刷新
f.flush()
## 注意
1. a模式下,文件不存在会创建文件
2. a模式下,文件存在会在最后追加写入文件
with open("bill.txt", "r", encoding="utf-8") as fr:
with open("bill.txt.bak", "w", encoding="utf-8") as fw:
for line in fr:
line = line.strip()
if line.strip(",")[4] == "测试":
continue
fw.write(line)
fw.write("\n")
当我们检测到一个错误时,Python解释器就无法继续执行了,反而出现了一些错误的提示,这就是所谓的“异常”我们常说的bug
try:
可能发生错误的代码
except:
如果出现异常执行的代码
# 需求,尝试以'r'模式打开文件,如果文件不存在,则以'w'方式打开
try:
f = open('linux.txt','r')
except:
f = open('linux.txt','w')
基本语法:
try:
print(name)
except NameError as e:
print("name未定义")
## 注意事项:
1. 如果尝试执行的代码得异常和要捕获的异常类型不一致,则无法捕获异常
2. 一般try下方只放一行尝试执行的代码
基本语法
## 当捕获多个异常时,可以把要捕获的异常类型的名字,放在except后,并用元组的方式进行书写
try:
print(1/0)
except (NameError, ZeroDivisionError) as e:
print("异常");
# 捕获所有的异常
try:
print(1/0)
except Exception as e:
print("异常");
else表示如果没有异常要执行的代码----可写可不写
try:
print(1/0)
except Exception as e:
print("异常");
else:
print("没有异常,执行的代码");
finally表示无聊是否异常都要执行的代码。例如关闭文件
try:
print(1/0)
except Exception as e:
print("异常");
else:
print("没有异常,执行的代码");
finally:
print("用了,一定会走")
异常是具有传递性的
当函数func01中发生异常,并且没有捕获处理这个异常的时候,异常会传递到函数fun02,当fun02也没有捕获处理这个异常的时候,main函数会捕获这个异常,这就是异常的传递性,
提示:
# 异常捕获
def fun01():
print("这是func01开始")
num = 1 / 0
print("这是func01结束")
def fun02():
print("这是func02开始")
fun01()
print("这是func02结束")
if __name__ == '__main__':
try:
fun02()
except Exception as e:
print(e)
############
这是func02开始
这是func01开始
division by zero
# 异常没有捕获
def fun01():
print("这是func01开始")
num = 1 / 0
print("这是func01结束")
def fun02():
print("这是func02开始")
fun01()
print("这是func02结束")
if __name__ == '__main__':
fun02()
################
这是func02开始
这是func01开始
Traceback (most recent call last):
File "D:\Desktop\pySpace\py-demo\exceptiondemo.py", line 14, in <module>
fun02()
File "D:\Desktop\pySpace\py-demo\exceptiondemo.py", line 9, in fun02
fun01()
File "D:\Desktop\pySpace\py-demo\exceptiondemo.py", line 3, in fun01
num = 1 / 0
~~^~~
ZeroDivisionError: division by zero
python模块(module)是一个python文件,以.py结尾,模块能定义函数,类和变量。模块里也能包含可执行的代码。
python中有很多各种不同的模块,每一个模块都可以帮助我们快速的实现一些功能,例如实现和时间相关的功能可以使用time模块,我们可以认为一个模块就是第一个工具包,每一个工具包都有各种不同的工具供我们使用,进而实现各种不同的功能,
模块在使用前需要先导入,导入的语法如下:
[from 模块名] import [模块 | 类 | 变量 | 函数 | *] [as 别名]
常用的组合:
# 使用import 导入time模块使用sleep功能
import time
time.sleep(2000)
# 使用from 导入time的sleep
from time import sleep
sleep(2000)
# 使用* 导入time模块的全部功能
from time import *
sleep(2000)
# 使用as给特定功能加上别名
from time import sleep as s
s(3000)
##### my_module
def test(a, b):
print(a + b)
##### my_module2
def test(a, b):
print(a - b)
#### my_module3
__add__ = ["test2", "test3"]
def test(a, b):
print(a - b)
def test2(a, b):
print(a * b)
def test3(a, b):
print(a / b)
# 导入自定义模块使用
import my_module
my_module.test(1, 2)
# 导入不同模块的同名功能
from my_module import test
from my_module2 import test
## 注意: 当导入多个模块的时候,且模块内有同名功能,当调用这个同名功能的时候,调用到的是后面导入的模块的功能
test(2, 1)
# __main__变量
只有当程序是直接执行的才会进入 if内部,如果是被导入的,则if无法进入
# __all__变量
# 如果一个模块文件中有‘__all__’变量,当使用‘from xxx import *’导入时,只能导入这个列表中的元素
import 包名.模块名 | 包名.模块名.目标
from 包名 import * | 模块名.目标
## 注意:必须在'__init__.py'文件里面添加'__add__ = []' 控制允许导入的模块列表
在python中有许多第三方包(非官方)
但是由于是第三方包,python没有内置,所以我们需要安装才可以导入使用
第三方包安装非常简单,只需要使用python内置的pip程序即可
my_utils包
# __init__.py
__all__ = ["str_util", "file_util"]
# file_util.py
def print_file_info(file_name):
f = open(file_name, "r", encoding="utf-8")
try:
context = f.read()
print(context)
except Exception:
print("文件不存在")
finally:
f.close()
def add_file_data(file_name, data):
with open(file_name, "a", encoding="utf-8") as f:
f.write(data)
f.close()
# str_util.py
def str_reverser(s):
return reversed(s)
def sub_str(s, x, y):
return s[x:y]
# mian中使用
from my_utils import str_util, file_util
if __name__ == '__main__':
print(str_util.str_reverser("asdfghj"))
print(str_util.sub_str("asdfghhh", 2, 6))
file_util.add_file_data("pydemo.txt", "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"\nxxxxxxxxxxxxxxxxxxxxxxxxxx")
file_util.print_file_info("pydemo.txt")
什么是json:
主要功能:json就是一种在各个编程语言中流通的数据格式,负责不同编程语言中的数据传递和交互,类似与
# 导入json模块
import json
# 准备符合格式json格式要求的python数据
data = [{"name":"老王", "age": 18},{"name":"老名", "age": 16}]
# 通过json.dumps(data)方法把python数据转成json数据
data = json.dumps(data)
print(data) # [{"name": "\u8001\u738b", "age": 18}, {"name": "\u8001\u540d", "age": 16}]
# 加入ensure_ascii=False [{"name": "老王", "age": 18}, {"name": "老名", "age": 16}]
# 通过json.loads(data)方法把json数据转化为python数据
data = json.loads(data)
print(data) # [{'name': '老王', 'age': 18}, {'name': '老名', 'age': 16}]
在程序中是可以做到和生活中那样,设计表格,生产表格,填写表格的组织形式的
# 设计一个类
class Student:
name = None
age = None
gender = None
# 创建一个对象
stu_1 = Student()
# 对象属性进行赋值
stu_1.name = "张三"
stu_1.age = 18
stu_1.gender = "女"
# 获取对象中记录的信息
print(stu_1.name, stu_1.age, stu_1.gender) # 张三 18 女
类的基本语法
class 类名称:
类的属性
类的行为
创建类对象的语法
对象 = 类名称()
class student:
name = None
age = None
def say_hi(self):
print(f"大家好,我是{self.name}")
可以看出:
其中:
在类中定义成员方法和定义函数基本一致,但仍有细微区别:
def 方法名(self, 形参1, …, 形参N):
方法体
可以看出,在方法定义的参数列表中,有一个:self关键字
self关键字是成员方法定义的时候,必须填写的。
** 什么是面向对象:使用对象进行编程**
设计类,基于类创建对象,并使用对象来完成具体的工作
Python类可以使用 init()方法,称之为构造方法。
可以实现:
class Student:
name = None
age = None
gender = None
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
stu_1 = Student("张三", 18, "女")
# 获取对象中记录的信息
print(stu_1.name, stu_1.age, stu_1.gender) # 张三 18 女
class Student:
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
stu_1 = Student("张三", 18, "女")
# 获取对象中记录的信息
print(stu_1.name, stu_1.age, stu_1.gender) # 张三 18 女
注意:
魔术方法:python把内置的类方法,称之为魔术方法
class Student:
name = None
age = None
gender = None
def __init__(self, name, age, gender):
self.name = name
self.age = age
self.gender = gender
def __str__(self):
return f"{self.name}:{self.age}:{self.gender}"
def __lt__(self, other):
return self.age < other.age
def __le__(self, other):
return self.age <= other.age
def __eq__(self, other):
return self.name == other.name
stu_1 = Student("张三", 18, "女")
stu_2 = Student("李四", 16, "男")
# 获取对象中记录的信息
print(stu_1.name, stu_1.age, stu_1.gender) # 张三 18 女
print(stu_1) # 张三:18:女
print(stu_1.__lt__(stu_2)) # False
print(stu_1.__le__(stu_2)) # False
stu_3 = Student("李wu", 16, "男")
print(stu_2.__le__(stu_3)) # True
stu_4 = Student("李四", 16, "男")
print(stu_2.__eq__(stu_4)) # True
面向对象编程:是许多编程语言都支持的一种编程思想
基于模板(类)去创建实体(对象),使用对象完成功能开发
面向对象三大主要特性:
类中提供了私有成员的形式来支持
定义私有成员的方式比较简单
即可完成私有成员的设置
# 定义一个类,包含私有成员变量和方法
class Student:
__name = None
__age = None
def __change_name(self, name):
self.__name = name
stu = Student()
# stu.__name = "张三" # 不报错
print(stu.__name) # 报错
#
stu.__change_name("Lisi") # 报错
私有成员无法被类对象使用,但是可以被其它的成员变使用
class 类名(父类名)
类内容体
##############单继承
class Phone:
IMEI = None
producer = "HW"
def call_by_4g(self):
print("4g")
class Phone2023(Phone):
face_id = "10001"
def call_by_5g(self):
print("2023 5G")
phone = Phone2023()
print(phone.producer) # HW
print(phone.IMEI) # None
phone.call_by_4g() # 4g
phone.call_by_5g() # 2023 5G
python的类之间也支持多继承,即一个类,也可以继承多个父类
语法:
class 类名(父类1, 父类2, …, 父类N)
类内容体
##############多继承
class Phone:
IMEI = None
producer = "HW"
def call_by_4g(self):
print("4g")
class NFC:
nfc_type = "第五代"
producer = "HW2"
def read_card(self):
print("nfc读卡")
def write_card(self):
print("nfc写卡")
class RemoteControl:
rc_type = "红外"
def control(self):
print("红外开启")
class Phone2023(Phone, NFC, RemoteControl):
pass #
phone = Phone2023()
print(phone.producer) # HW
print(phone.IMEI) # None
phone.call_by_4g() # 4g
phone.write_card() # nfc写卡
phone.read_card() # nfc读卡
phone.control() # 红外开启
补充:
pass是占位语句,用来保证函数(方法)或者类定义的完整性,表示无内容,空的意思
子类继承父类的成员属性和成员方法后,如果对其不满意,可以进行复写
即:在子类中重新定义同名的属性或者方法即可
##############复写
class Phone:
IMEI = None
producer = "HW"
def call_by_4g(self):
print("4g")
class Phone2023(Phone):
producer = "XIAOMI"
def call_by_4g(self):
print("4g加速")
phone = Phone2023()
print(phone.producer) # XIAOMI
print(phone.IMEI) # None
phone.call_by_4g() # 4g加速
调用父类同名成员
一旦复写父类成员,那么类对象调用成员的时候,就会调用复写后的新成员
如果需要使用被复写的父类的成员,需要特殊的调用方式
方式1:
方式2:
注意:只可以在子类内部调用父类的同名成员,子类的实体类对象调用默认的是调用子类复写的
基本语法:变量:类型
基本数据类型注解
var_1: int = 10
var_2: float = 20.2
var_3: bool = True
var_4: str = “xxxx”
类对象注解
class student:
pass
stu: Student = Student()
基础容器类型注解
my_list: list = [1, 2, 3]
my_tuple: tuple = (1, 2, 3)
my_set: set = {1, 2, 3}
my_dict: dict = {“xxx”: 444}
my_str: str = “xxxxxxx”
容器类型详细注解
my_list: list[int] = [1, 2, 3]
my_tuple: tuple[str, int, bool] = (“xxxx”, 1, True)
my_set: set[int] = {1, 2, 3}
my_dict: dict[str, int] = {“xxx”: 444}
注意:
除了使用变量: 类型,也可以在注释中进行类型注解
语法:#type: 类型
在注释中进行类型注解
class Student:
pass
var_1 = random.randint(1, 10) # type: int
var_2 = json.loads(data) # type: dict[str, int]
var_3 = func() # type: Student
类型注解的主要功能:
并不会真正对类型做验证和判断,也就是,类型注解仅仅是提示性的,不是决定性的
函数和方法的形参类型注解语法
def 函数方法名(形参名: 类型, 形参名: 类型, …):
pass
返回值注解:
ddef 函数方法名(形参名: 类型, 形参名: 类型, …) -> 返回值类型:
pass
from typing import Union
my_list: list[Union[str, int]] = [1, 2, “xxxx”, “cccc”]
my_dict: dict[str, Union[str, ing]] = {“xxx”: “xxx”, “vvv”: 12}
可以使用Union[类型, …, 类型],可以定义联合类型注解
在函数方法注解形参和返回值
def func(data: Union[str, int]) -> Union[str, int]:
pass
指的是:多种状态,即完成某个行为时,使用不同的对象会得到不同的状态
多态常用在继承上:
比如
即:
抽象类:含有抽象方法的类称之为抽象类
抽象方法:方法体是空实现(pass)称之为抽象方法
class Animal:
def speak(self):
pass
class Dog(Animal):
def speak(self):
print("汪汪汪")
class Cat(Animal):
def speak(self):
print("喵喵喵")
这种设计的含义是:
这种写法,就叫抽象类(也称之为接口)
抽象类的作用:
定义:在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们吧这个使用外部函数变量的内部函数称之为闭包。
简单的闭包:
def outer(logo):
def inner(msg):
print(f"<{logo}>{msg}<{logo}>")
return inner
fn1 = outer("ccc") # fn1就等于 inner方法
fn1("yyy") # cccyyyccc
fn1("hhh") # hhhyyyhhh
使用nonlocal关键字修饰外部函数的变量,才可以在内部函数中修改它
def outer(num1):
def inner(num2):
nonlocal num1
num1 += num2
print(num1)
fn1 = outer(10)
fn1(10) # 20
fn1(10) # 30
闭包的好处和缺点:
nonlocal关键字的作用:
在闭包函数(内部函数中)想要修改外部函数的变量值需要使用nonlocal声明这个外部变量
其实就是一种闭包,其功能就是在不破坏目标函数原有的代码和功能的前提下,为目标函数增加新功能
def sleep():
import random
import time
print("睡眠中")
time.sleep(random.randint(1, 5))
### 在调用前,打印我要睡觉了 执行完成后打印我起床了
# 定义一个闭包函数,在闭包方法函数内部
# 1. 执行目标函数
# 2. 并完成功能的添加
def outer(func):
def inner():
print("我要睡觉了")
func()
print("我起床了")
fn = outer(sleep)
fn()
@outer
def sleep():
import random
import time
print("睡眠中")
time.sleep(random.randint(1, 5))
### 在调用前,打印我要睡觉了 执行完成后打印我起床了
# 定义一个闭包函数,在闭包方法函数内部
# 1. 执行目标函数
# 2. 并完成功能的添加
def outer(func):
def inner():
print("我要睡觉了")
func()
print("我起床了")
sleep()
## 工具类包
class strTools:
pass
str_tool = StrTools()
# 引用文件
from test import str_tool
s1 = str_tool
s2 = str_tool
## 同一个对象
import time
import threading
def sing():
while True:
print("我在唱歌")
time.sleep(1)
def dance():
while True:
print("我在跳舞")
time.sleep(1)
if __name__ == '__main__':
sing_thread = threading.Thread(target=sing, name="唱歌线程")
dance_thread = threading.Thread(target=dance, name="跳舞线程")
sing_thread.start()
dance_thread.start()
import time
import threading
def sing(msg):
while True:
print(msg)
time.sleep(1)
def dance(msg):
while True:
print(msg)
time.sleep(1)
if __name__ == '__main__':
sing_thread = threading.Thread(target=sing, name="唱歌线程", args=("我在唱歌",))
dance_thread = threading.Thread(target=dance, name="跳舞线程", kwargs={"msg": "我在跳舞"})
sing_thread.start()
dance_thread.start()
https://flet.dev/docs/guides/python/getting-started
from datetime import datetime, date
from typing import List, Optional
from pydantic import BaseModel, ValidationError
"""
Data validation and settings management using python type annotations
使用python的类型注解来进行数据校验和setting管理
pydantic 可以在代码运行时提供类型提示,数据校验失败时提供友好的错误提示
定义数据应该如果在纯规范的python代码中保存,并用pydantic验证它
"""
class User(BaseModel):
id: int # 必填字段
name: str = "xxxx" # 有默认值选填字段
signup_ts: Optional[datetime] = None
friends: List[int] = [] # 列表中元素使int类型或者可以直接转换成int类型 “1”
external_data = {
"id": "123",
"signup_ts": "2023-12-12 12:22",
"friends": [1, 2, "3"]
}
user = User(**external_data)
print(user.id, user.name, user.signup_ts, user.friends)
print(repr(user.signup_ts)) # __repr__主要用于调试和开发,而__str__用于为最终用户创建输出。 __repr__打印datetime.datetime(2023, 12, 12, 12, 22)
print(dict(user))
# ------------------- 校验失败处理
try:
User(id=1, signup_ts=datetime.today(), friends=[1, 2, "not number"])
except ValidationError as e:
print(e.json())
# --------------------------模型类的属性和方法
print(user.dict)
print(user.json)
print(user.copy) # 这里是浅拷贝
# print(user.parse_obj(obj=external_data))
# print(user.parse_raw())
class Sound(BaseModel):
sound: str
class Dog(BaseModel):
birthday: date
weight: float = Optional[None]
sound: List[Sound]
# 文件名称main.py
from typing import Optional
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
is_offer: Optional[bool] = None
@app.get("/")
def read_root():
return {"Hello": "World"}
@app.get("/items/{item_id}") # q为?后面参数 /item/1?q="xxx"
def read_item(item_id: int, q: Optional[str] = None):
return {"item_id": item_id, "q": q}
@app.put("/items/{item_id}")
def update_item(item_id: int, item: Item): # item json参数
return {"item_name": item.name, "item_id": item_id}
######启动命令:uvicorn main:app --reload # --reload 修改内容服务器会重载
from datetime import date
from enum import Enum
from typing import Optional, List
from pydantic import BaseModel, Field
from fastapi import APIRouter, Path, Query, Cookie, Header # path 校验路径参数用
app03 = APIRouter()
"""
路径参数和数字验证
"""
@app03.get("/path/parameters")
def path_params01():
return {"message": "This is a message"}
@app03.get("/path/{parameters}")
def path_params01(parameters: str): # 函数的顺序就是路由的顺序
return {"message": parameters}
class CityName(str, Enum):
BEI_JING = "beijing china"
SHANG_HAI = "shanghai china"
@app03.get("/enum/{city}")
async def latest(city: CityName):
if city == CityName.SHANG_HAI:
return {"city_name": city, "confirmed": 1492, "death": 7}
if city == CityName.BEI_JING:
return {"city_name": city, "confirmed": 971, "death": 9}
return {"city_name": city, "latest": "unknown"}
@app03.get("/files/{file_path:path}") # 通过path parameters传递文件路径 添加:path 表示file_path有/ 不作为路径,而是文件路径参数
def print_file_path(file_path: str):
return f"the file_path is {file_path}"
@app03.get("/path_num/{num}")
def path_params_validate(num: int = Path(None, ge=1, le=10, title="你的数字参数", description="不可描述")):
return num
"""
查询参数和数据的解析。验证
"""
@app03.get("/query")
def page_limit(page: int = 1, limit: Optional[int] = None): # 给了默认值就是选填的参数
if limit:
return {"page": page, "limit": limit}
return {"page": page}
@app03.get("/query/bool/conversion")
def type_conversion(param: bool = False): # bool类型转换:yes on 1 True 会转换成True
return param
@app03.get("query/validations")
def query_params_validate(value: str = Query(..., min_length=8, max_length=16, regex="^a"),
values: List[str] = Query(default=["v1", "v2"], alias="alias_name")):
return values, value
"""
请求体和字段
"""
class CityInfo(BaseModel):
name: str = Field(..., example="beijing") # example是注解的作用,值不会被认证
country: str
country_code: str = None # 给定一个默认值
country_population: int = Field(default=800, title="人口数量", description="国家的人口数量", ge=800)
class config:
schema_extra = {
"example": {
"name": "beijing",
"country": "china",
"country_code": "CN",
"country_population": 140000000
}
}
@app03.post("/request_boby/city")
def city_info(city: CityInfo):
print(city.name, city.country, city.country_code, city.country_population)
return city.model_dump_json()
"""
多参数混合
"""
@app03.post("/query_city/{name}")
def mix_city_info(
name: str,
city01: CityInfo,
city02: CityInfo,
confirmed: int = Query(ge=0, description="确诊数", default=0),
death: int = Query(ge=0, description="死亡数", default=0)
):
return city01.model_dump_json(), city02.model_dump_json()
"""
数据格式嵌套的请求体
"""
class Data(BaseModel):
city: List[CityInfo] = None # 这里是定义数据格式嵌套的请求体
data: date # 额外的数据类型,还有uuid,datetime, bytes, frozenset,
confirmed: int = Field(ge=0, description="确诊数", default=0)
deaths: int = Field(ge=0, description="死亡数", default=0)
recovered: int = Field(ge=0, description="死亡数", default=0)
@app03.post("/query_body/nested")
def nested_models(data: Data):
return data
"""
Cookie 和 Header 参数
"""
app03.get("/cookie")
def cookie(cookie_id: Optional[str] = Cookie(None)): # 定义cookie参数需要使用到Cookie类
return {
"cookie_id": cookie_id
}
@app03.get("/header")
def header(user_agent: Optional[str] = Header(None, convert_underscores=True),
x_token: List[str] = Header(None, convert_underscores=True)): # convert_underscores 表示是否转换下划线 user_agent -- userAgent
return {
"header": user_agent,
"x_token": x_token
}
**概念:**在同一线程内,一段执行代码过程中,可以中断并跳转到另一端代码中,接着之前中断的地方继续执行,协程运行状态于多线程类似。
协程优点:
协程缺点:
实现协程的办法:
# def func():
# print("当前是一个生成器函数")
# while True:
# """
# 下面没有代码,会暂停,下一次运行的时候接着上一次运行的位置继续运行
# """
# yield '这是生成器函数返回的数据。。。'
#
#
# obj = func() # 返回一个对象,生成器对象
# print(obj) #
# print(next(obj)) # 生成器需要通过next()方法进行驱动
"""
中断暂停的特点:
在运行第一个任务的使用遇到yield暂停并切换到另一个任务上继续执行
"""
# 利用生成器特性进行任务切换
import time
def func_a():
while True:
print("这是func_a函数")
yield
time.sleep(0.5)
def fun_b(obj):
while True:
print("这是func_b")
obj.__next__()
a = func_a()
fun_b(a)
import asyncio
@asyncio.coroutine
def func1():
print(1)
yield from asyncio.sleep(2) # 遇到IO耗时,自动化切换到tasks中的其他任务
print(2)
@asyncio.coroutine
def func2():
print(3)
yield from asyncio.sleep(2) # 遇到IO耗时,自动化切换到tasks中的其他任务
print(4)
tasks = [
asyncio.ensure_future(func1()),
asyncio.ensure_future(func2())
]
loop = asyncio.get_event_loop()
loop.run_until_complete(asyncio.wait(tasks))
import asyncio
import time
async def say_after(delay, what):
await asyncio.sleep(delay)
print(what)
async def main():
print(f"started at {time.strftime('%X')}")
await say_after(1, 'hello')
await say_after(2, 'world')
print(f"finished at {time.strftime('%X')}")
asyncio.run(main())
def func():
time.sleep(1)
now = lambda: time.time()
start = now()
for i in range(5):
func()
print("同步所花费的诗句:%f s" % (now() - start))
### 同步所花费的诗句:5.002251 s
async def func(x):
await asyncio.sleep(1)
print(x)
for i in range(5):
asyncio.run(func(i))
print("异步所花费的诗句:%f s" % (now() - start))
理解成一个死循环,去检测并执行某些代码
任务列表 = [任务1, 任务2, 任务3, ...]
while True:
可执行的任务列表,已完成的任务列表,去任务列表中检查所有的任务,将可执行和已完成的任务返回
for 就绪任务 in 可执行的任务列表:
执行已就绪的任务
for 完成任务 in 已完成的任务列表:
在任务列表中移除已完成任务
如果任务列表中的任务都已完成,则终止循环
import asyncio
# 去生成或获取一个事件循环
loop = asyncio.get_event_loop()
# 将任务放到任务列表中去
loop.run_until_complete(任务)
协程函数,定义函数时候,async def 函数名
协程对象,执行协程函数() 得到的协程 对象
async def func():
pass
result = func()
注意:执行协程函数创建协程对象,函数内部代码不执行
如果想要运行协程函数内部代码,必须要讲协程对象交给事件循环来处理
import asyncio
async def func():
print("111")
result = func()
# 去生成或获取一个事件循环
loop = asyncio.get_event_loop()
# 将任务放到任务列表中去
loop.run_until_complete(result)
await + 可等待对象(协程对象,Future,Task对象 -> IO等待)
import asyncio
async def func():
print("1111")
response = await asyncio.sleep(2)
print("结束", response)
asyncio.run(func())
import asyncio
async def others():
print("start")
await asyncio.sleep(2)
print("end")
return "返回值"
async def func():
print("执行协程函数内部代码")
# 遇到IO操作挂起当前协程(任务) 等待IO操作完成之后再继续往下执行,当前协程挂起时,事件循环可以去执行其他协程(任务)
response = await others()
print("IO请求结果结束,结果:", response)
asyncio.run(func())
await就是等待对象的值得到结果之后再继续往下走
在事件循环中添加多个任务
Tasks用于并发调度协程,通过asyncio.create_task(协程对象)的方式来创建Task对象,这样可以让协程加入事件循环中等待被调度执行,除了使用了asyncio.create_task()函数外,还可以使用低层级的loop.create_task()或者ensuer_future函数,不建议手动实例化Task对象
import asyncio
async def others():
print("start")
await asyncio.sleep(2)
print("end")
return "返回值"
async def func():
print("执行协程函数内部代码")
# 遇到IO操作挂起当前协程(任务) 等待IO操作完成之后再继续往下执行,当前协程挂起时,事件循环可以去执行其他协程(任务)
response = await others()
print("IO请求结果结束,结果:", response)
async def main():
print("main开始")
# 创建Task对象,将当前执行func函数任务添加到事件循环
task1 = asyncio.create_task(func())
task2 = asyncio.create_task(func())
print("main结束")
# 当执行某协程遇到的IO操作时,会自动化切换执行其他任务
# 此处的await是等待相对应的协程全部执行完毕并获取结果
result = await task1
resule2 = await task2
print(result, resule2)
asyncio.run(main())
import asyncio
async def others():
print("start")
await asyncio.sleep(2)
print("end")
return "返回值"
async def func():
print("执行协程函数内部代码")
# 遇到IO操作挂起当前协程(任务) 等待IO操作完成之后再继续往下执行,当前协程挂起时,事件循环可以去执行其他协程(任务)
response = await others()
print("IO请求结果结束,结果:", response)
async def main():
print("main开始")
task_list = [
asyncio.create_task(func(), name="task1"),
asyncio.create_task(func(), name="task2")
]
print("main结束")
done, pending = await asyncio.wait(task_list, timeout=None) # done 收到一个已经完成的集合,pending是没有完成的集合
print(done, pending)
asyncio.run(main())
import asyncio
async def others():
print("start")
await asyncio.sleep(2)
print("end")
return "返回值"
async def func():
print("执行协程函数内部代码")
# 遇到IO操作挂起当前协程(任务) 等待IO操作完成之后再继续往下执行,当前协程挂起时,事件循环可以去执行其他协程(任务)
response = await others()
print("IO请求结果结束,结果:", response)
task_list = [
func(),
func()
]
done, pending = asyncio.run(asyncio.wait(task_list))
print(done)
Task是继承Future, Task对象内部await结果的处理基于Future对象来的
import asyncio
async def main():
# 获取当前循环事件
loop = asyncio.get_running_loop()
# 创建一个任务(Future)对象,这个任务什么都不干
fut = loop.create_future()
# 等待任务最终结果,没要结果则会一直等下去
await fut
asyncio.run(main())
import asyncio
async def set_after(fut):
await asyncio.sleep(2)
fut.set_result("6666")
async def main():
# 获取当前循环事件
loop = asyncio.get_running_loop()
# 创建一个任务(Future)对象,这个任务什么都不干
fut = loop.create_future()
# 创建一个任务Task对象,绑定了set_after函数,函数在内部2s之后会给fut赋值
# 即手动设置future任务的最终结果,那么fut就可以结束了
await loop.create_task(set_after(fut))
# 等待任务最终结果,没要结果则会一直等下去
date = await fut
print(date)
asyncio.run(main())
使用线程池,进程池实现异步操作时用到的对象
import time
from concurrent.futures.thread import ThreadPoolExecutor
def func(value):
time.sleep(1)
print(value)
pool = ThreadPoolExecutor(max_workers=5)
# 或者 ProcessPoolExecutor(max_workers=5)
for i in range(10):
fut = pool.submit(func, i)
print(fut)