1.初识函数
# 定义函数
def 函数名():
'代码'
...
# 调用函数
函数名()
函数应用场景:
- 面向过程编程,从上到下按照业务逻辑功能逐一实现。
print("xx监控系统")
if cpu使用率 > 90%:
发送邮件报警
if cpu使用率 > 90%:
发送邮件报警
if cpu使用率 > 90%:
发送邮件报警
- 面向对象编程。(函数式编程)
def 发送邮件():
发送邮件
print("xx监控系统")
if cpu使用率 > 90%:
发送邮件()
if cpu使用率 > 90%:
发送邮件()
if cpu使用率 > 90%:
发送邮件()
函数编程的特点和应用场景:
- 反复使用某个代码段,利用函数【增强代码的重用性】
- 将代码拆分到不同的函数,【增强代码的可读性】
2.基本使用
def send_email(x1, x2):
pass
# 位置传参
send_email(123, 22)
# 关键字传参
send_email(x2=123, x1=22)
# 混合使用(关键字在后)
send_email(123, x2=22)
####注意:参数可以是任意类型,也就是说,任意类型的数据都可以做参数传入
- 参数默认值
def send_email(x1, x2, x3=999): pass
- 参数的默认值中出现了 可变类型 需要谨慎考虑
def func(a1=[]):
a1.append(2)
print(a1)
func() # [2]
func([]) # [2]
func() # [2, 2]
# 错误分析:执行函数未传递参数,不会每次都重新创建空列表。
- 动态参数
- 一个星号:*
def func(*a1): # 会将传进来的参数打包为一个元组 pass func(1, 22, 123) ---> a1 = (1, 22, 123) func("xxx", 123) ---> a1 = ("xxx", 123) func([1, 22], 123) ---> a1 = ( [1, 22], 123 ) func(1) ---> a1 = (1,) func( (1, 22, 123) ) ---> a1 = ( (1, 22, 123), )
- 两个星号:**
def func(**a2): # 会将传进来的参数打包为一个字典 pass func(v1=123, v2=456) ---> a2 = {"v1": 123, "v2": 456} func() ---> a2 = {} func(uu=999) ---> a2 = {"uu": 999}
- 两种星号混合使用:*,**
def func(*a1, **a2): pass func(1,2) ---> a1=(1, 2) a2={} func(v1=123, v2=456) ---> a1=() a2={"v1": 123, "v2": 456} func(99, data=123) ---> a1=(99,) a2={"data": 123}
代表函数是 format函数:def format(self, *args, **kwargs)
易错点:
def f1(*args, **kwargs): # args=( [111,222,33], ) # args=( (111,222,33), ) # kwargs={ "v1": (111,222,33) } pass f1([111,222,33]) f1((111,222,33)) f1(v1=(111,222,33))
- 一个星号:*
函数参数传递方式,是引用还是值?
def func(arg):
print(arg)
name = "xxx"
func(name)
# 传递的是引用,不会重新拷贝一份数据,再传入到参数中
资料来源:https://zhuanlan.zhihu.com/p/362702418
Python 中参数的传递既不是值传递,也不是引用传递,而是赋值传递,或者是叫对象的引用传递。
需要注意的是,这里的赋值或对象的引用传递,不是指向一个具体的内存地址,而是指向一个具体的对象。
1、如果对象是可变的,当其改变时,所有指向这个对象的变量都会改变。
2、如果对象不可变,简单的赋值只能改变其中一个变量的值,其余变量则不受影响。
3.作用域
作用域,一块共享的区域。
name = "aaa"
def func():
global name
name = "bbb"
print(name)
func()
print(name)
4.函数名也是一个变量名称
- 函数名有"()", 代表是执行函数,如果没有”()“,则函数名作为一个变量,例如:
def f1():
pass
f2 = f1() # 这句代码的意思是将f1函数的执行结果赋值给f2
f3 = f1 # 这行代码意思是将f1函数名赋值给f3,f3将和f1一样拥有相同的函数逻辑,后期可以使用f3
res = f3() # res是f3执行结果,和res = f1()执行结果相同
# 如何执行这些函数更简便
def send_sms():
print("发送短信")
def send_email():
print("发送邮件")
def send_dingding():
print("发送钉钉")
def send_wechat():
print("发送微信")
func_list = [send_sms, send_email, send_dingding, send_wechat]
for func in func_list:
func()
5.匿名函数(lambda表达式)
def func(x, y):
return 100 + y
func = lambda x,y: 100+y
6.函数进阶
-
内置函数
- 第一组
- open
f = open("xxx", mode="rb") f.read() f.close()
- len
v1 = [111, 22] v2 = "abc" len(v1) len(v2)
- range
v1 = range(5) # [0,1,2,3,4]
- abs,求绝对值
v1 = abs(-10) print(v1) # 10
- pow,次方
pow(2, 5) # 计算 2 的 5 次方 # 或者 v1 = 2 ** 5
- sum,求和
data = [11, 22, 33] res = sum(data)
- divmod, 两个数相除得到商和余数
v1, v2 = divmod(98, 10) # v1 = 9, v2 = 8
- round,保留小数后几位
v1 = round(3.1415926, n) # 自动四舍五入,保留 n 位小数
- 第二组
- min,取最小值
v1 = [11,22,33] res = min(v1) # 11
- max,取最大值
v1 = [11,22,33] res = max(v1) # 33
- all,检测元素是否全部都是True(类型会转换为bool值)
v1 = [11,22,33] res = all(v1) # True v2 = [11,22,"",33] res = all(v2) # False
# 使用场景 user = input("用户名:") pwd = input("密码:") is_valid = all([user, pwd]) if is_valid: print(user, pwd) else: print("用户名或密码为空,请重新输入")
- any,只要有True就行
v1 = [11,22,33,0,""] res = any(v1) # True v2 = [0, ""] res = any(v2) # False
- 第三组
- 进制,计算机底层本质都是二进制,即01代码
v1 = 90 # 十进制 v2 = "0b011011" # 二进制 v3 = "0o0523" # 八进制 v4 = "0x0ab" # 十六进制
- 十进制和二进制
十 --> 二 v1 = bin(90) 二 --> 十 int("0b011011", base=2) # base指是几进制
- 十进制和八进制
十 --> 八 oct(90) 八 --> 十 int("0o0523",base=8)
- 十进制和十六进制
十 --> 十六 hex(90) 十六 --> 十 int("0x0ab",base=16)
- 进制转换练习题
将一个IP地址:ip = "192.168.11.23",将ip地址转换为二进制 192 --> 0110110 168 --> 1011010 11 --> 0110 23 --> 10110 拼接起来 01101101011010011010110 转换成十进制数
ip = "192.168.11.23" ip_list = list() for ip_item in ip.split("."): ip_list.append(bin(int(ip_item))[2:]) # 使用[2:]切片的原因是转换为二进制后前缀有“0b” # 次数可知,字符串拼接的效率比join的效率低,join的效率高 print(int("".join(ip_list),base=2))
ip = "192.168.11.23" ip_list = list() for ip_item in ip.split("."): ip_list.append(bin(int(ip_item))) # 次数可知,字符串拼接的效率比join的效率低 print(int("".join(ip_list).replace("0b", ""),base=2))
- 第四组
unicode是万国码,所有文字和二进制之间对应关系- ord
v1 = ord("A") # 65
- chr
v1 = chr(65) # "A"
- 第五组
- int
- str
- bool
- list
- dict
- tuple
- float
v1 = "3.14" res = float(v1) # 3.14
- bytes
v1 = "abc" res = v1.encode("utf8") # 字节类型
res = bytes("abc", encoding="utf8") # 与上面相同
- 第六组
- len
- input
- open
- range
- hash
计算一个值的哈希值(作为建来存储) - type
- callable
判断是否可执行 --> 函数名
v1 = "root" res = callable(v1) # False
def v1(): pass res = callable(v1) # True
def func(): print("我是个函数执行的结果") data_list = [11,22,55,func] for item in data_list: if callable(item): item() else: print(item) # 11 # 22 # 55 # 我是个函数执行的结果
- enumerate
循环过程中,自动为你生成一列。
# 以前生成带序号的方法 goods = ["手机", "电脑", "小汽车"] for item in range(len(goods)): print(item, goods[item]) for item in range(len(goods)): print(item+1, goods[item])
goods = ["手机", "电脑", "小汽车"] # 使用enumerate函数实现 enumerate(可迭代数据类型,标号起始位置) for index, item in enumerate(goods, 1): print(index, item) # 1 手机 # 2 电脑 # 3 小汽车
- sorted
排序
可以对可变数据排序 num_list = [10, 88, 15, 6, 46, 12] res1 = sorted(num_list) # [6, 10, 12, 15, 46, 88] res2 = sorted(num_list, reverse=True) # [88, 46, 15, 12, 10, 6] 可以对不可变数据排序 num_str = "dhqihdqd" res1 = sorted(num_list) res2 = sorted(num_list, reverse=True) # ['q', 'q', 'i', 'h', 'h', 'd', 'd', 'd']
sorted函数可以通过key指定排序的规则,接受的是一个函数的返回值作为排序依据 # 新问题:如果有需求,通过序号进行排序 num_list = ["1.python基础.mp4", "2.环境搭建.mp4", "3.pycharm安装.mp4", "10.总结"] # 正常排序后 print(sorted(num_list)) # ['1.python基础.mp4', '10.总结', '2.环境搭建.mp4', '3.pycharm安装.mp4'] # sorted函数可以指定排序规则 sorted(num_list, key=接受的是一个函数的返回值) 会按照接受的函数返回的值作为排序依据进行排序 def func(ele): return int(ele.split(".")[0]) print(sorted(num_list, key=func)) # ['1.python基础.mp4', '2.环境搭建.mp4', '3.pycharm安装.mp4', '10.总结'] # 可以将上述代码简化,使用lambda函数 print(sorted(num_list, key=lambda ele:int(ele.split(".")[0]))) # ['1.python基础.mp4', '2.环境搭建.mp4', '3.pycharm安装.mp4', '10.总结']
注意
sorted函数是将原有数据进行排序后生成一个新的列表,不论是可变或者不可变数据,经过排序后返回的都是一个列表
提出问题:sorted函数可以生成排序后的新列表,那么列表的sort函数呢,是新生成一个列表还是将原有列表进行排序? num_list = [10, 88, 15, 6, 46, 12] print("num_list使用sorted函数前的结果为{}".format(num_list)) # [10, 88, 15, 6, 46, 12] res1 = sorted(num_list) # [6, 10, 12, 15, 46, 88] print("num_list使用sorted函数后的结果为{}".format(num_list)) # [10, 88, 15, 6, 46, 12] print("num_list使用列表的.sort()方法前的结果为{}".format(num_list)) # [10, 88, 15, 6, 46, 12] res2 = num_list.sort() # res2 值为None,说明sort方法是在原有的列表上进行排序,没有返回值 print("num_list使用列表的.sort()方法后的结果为{}".format(num_list)) # [6, 10, 12, 15, 46, 88]
- 第一组
-
生成器
定义函数时,出现yield关键字,此函数就是一个生成器函数
def func(): print("abc") yield 1 yield 2 yield 3 # 执行生成器函数,会返回一个生成器对象 obj = func() # obj是一个生成器对象 # 生成器对象.__next__(),就会进入函数去执行,一旦遇到了yield,会跳出函数 obj.__next__()
生成器有什么用?
需求:创建1000W个数字方案1: 在内存中先创建列表[0,1,2,3...],再循环输出。 会占用大量内存,不实际
方案2: 不真创建,代码逻辑后续逐一生成数字,循环获取 def creat_num(total): num = 0 while num < total: yield num num += 1 res = creat_num(100) # 返回的是一个生成器对象 for item in res: print(item)
理解:生成器到底是怎么回事?
执行过程 + 优势 在python2中, range()函数是在内存中生成一系列数 -- 速度较慢 xrange()函数是类似于生成器的方法实现 -- 速度快 在python3中,在python2的基础上,升级为 range()函数使用的也是类似于生成器的方法,边调用,边生成
-
高阶函数,闭包
name = "root" def func(): v1 = 123 def inner(): print(666) return inner res = func() print(666) res() # 只有当调用这个函数时,才会执行
闭包,通过函数嵌套的机制,先将数据封装到作用域(包),后续再执行内部函数时,再去获取之前封装进去的值即可。
-
结合线程池 + 闭包完成批量下载的一个使用案例
import time from concurrent.futures import ThreadPoolExecutor import requests # 要干的活 def task(url): # 下载 res = requests.get(url) return res.content def outer(file_name): def done(response): """将下载的内容写到文件,需要知道下载的那个文件名""" with open(file_name, mode="wb") as f: f.write(response.result()) return done # def test(response): # print("test,{}".format(response)) # 线程池中最多创建5个线程 pool = ThreadPoolExecutor(5) img_list = [ {"file_name": "比亚迪.jpg", "url": "https://car3.autoimg.cn/cardfs/product/g26/M06/89/23/380x285_0_q87_autohomecar__CjIFVmQ2i1mAF0lRACGN6qouWmA140.jpg"}, {"file_name": "朗逸.jpg", "url": "https://car2.autoimg.cn/cardfs/product/g27/M03/D3/67/380x285_0_q87_autohomecar__ChxkmWLmMI2ACHSvABBW_v_Ebv0632.jpg"}, {"file_name": "雷凌.jpg", "url": "https://car2.autoimg.cn/cardfs/product/g26/M02/94/F0/380x285_0_q87_autohomecar__ChxkjmQbHTWAfiu1AA2Qc45KmBk129.jpg"}, {"file_name": "比亚迪2.jpg", "url": "https://car3.autoimg.cn/cardfs/product/g26/M06/89/23/380x285_0_q87_autohomecar__CjIFVmQ2i1mAF0lRACGN6qouWmA140.jpg"}, {"file_name": "朗逸2.jpg", "url": "https://car2.autoimg.cn/cardfs/product/g27/M03/D3/67/380x285_0_q87_autohomecar__ChxkmWLmMI2ACHSvABBW_v_Ebv0632.jpg"}, {"file_name": "雷凌2.jpg", "url": "https://car2.autoimg.cn/cardfs/product/g26/M02/94/F0/380x285_0_q87_autohomecar__ChxkjmQbHTWAfiu1AA2Qc45KmBk129.jpg"}, {"file_name": "比亚迪3.jpg", "url": "https://car3.autoimg.cn/cardfs/product/g26/M06/89/23/380x285_0_q87_autohomecar__CjIFVmQ2i1mAF0lRACGN6qouWmA140.jpg"}, {"file_name": "朗逸3.jpg", "url": "https://car2.autoimg.cn/cardfs/product/g27/M03/D3/67/380x285_0_q87_autohomecar__ChxkmWLmMI2ACHSvABBW_v_Ebv0632.jpg"}, {"file_name": "雷凌3.jpg", "url": "https://car2.autoimg.cn/cardfs/product/g26/M02/94/F0/380x285_0_q87_autohomecar__ChxkjmQbHTWAfiu1AA2Qc45KmBk129.jpg"}, ] # 10个任务 for item in img_list: fur = pool.submit(task, item.get("url")) fur.add_done_callback(outer(item.get("file_name"))) # fur.add_done_callback(test) # 分析可得,add_done_callback()所需的参数是函数名,会将传入的函数名进行执行
-
装饰器
def func(): print("我是func函数") return "中国万岁" def outer(func): def inner(): print("before") result = func() print("after") return result return inner func = outer(func) res = func()
装饰器优势:不修改原函数内容的前提下,进行了功能的扩展
Python中的装饰器,本质上就是利用:- 嵌套 + 闭包
- @xx语法糖
构建出来的一个功能,满足在不修改原函数内部代码的前提下,可以在函数执行前和后扩展我们自定义的功能。
# 装饰器一般格式 def outer(func): def inner(): # 扩展功能 res = func() return res return inner @outer def func(): print(123) return 999
-
推导式(不属于函数,额外内容)
用更少的代码,实现某个特定的功能 -
需求:创建一个列表,列表 = ["用户-0", "用户-1", "用户-3"...50个]
不使用推导式的常规方法
data_list = [] for i in range(51): data_list.append("用户-{}".fromat(i)) print(data_list)
-
列表推导式
data_list = [ i for i in range(51) ] # [0,1,2,3,4,5,6,...]
data_list = [ 100 for i in range(51) ] # [100,100,100,100...]
使用列表推导式完成上述需求
data_list = [ "用户-{}".format(i) for i in range(51) ]
列表推导式添加条件
data_list = [ i for i in range(51) if i > 9]
file_list = ["day01_python基础.mp4","day02_环境搭建.mp4","day03_pycharm安装.mp4","day10_总结","a1.png"] # 将day开头的文件提取到新的列表 result = [item for item in file_list if item.startswith("day")] # 将以mp4为结尾的文件提取出来 result = [item for item in file_list if item.endswith("mp4")]
练习:使用列表推导式,生成一个列表,下标位置的数值为此下标之前的总和,可以使用sum函数
# 要求 ans = [0, 1, 3, 6, 10] # 0 1 2 3 4 # 分析过程 # result = [] # for i in range(10): # result.append(sum(range(0,i+1))) # 答案 result = [sum(range(0, i+1)) for i in range(10)] print(result) # [0, 1, 3, 6, 10, 15, 21, 28, 36, 45]
-
字典推导式
info = {i:123 for i in range(10)} # {1:123,2:123,3:123...}
info = {i:123 for i in range(10) if i > 5} # {6:123,7:123,8:123...}
-
练习题
1.给一个列表,将列表中的每一个元素尾部.mp4剔除。
data_list = [ '1-5 编译器和解释器.mp4', '1-17 今日作业.mp4', '1-9 Python解释器种类.mp4', '1-16 今日总结.mp4', '1-2 课堂笔记的创建.mp4', '1-15 Pycharm使用和破解(win系统).mp4', '1-12 python解释器的安装(mac系统).mp4', '1-13 python解释器的安装(win系统).mp4', '1-8 Python介绍.mp4', '1-7 编程语言的分类.mp4', '1-3 常见计算机基本概念.mp4', '1-14 Pycharm使用和破解(mac系统).mp4', '1-10 CPython解释器版本.mp4', '1-1 今日概要.mp4', '1-6 学习编程本质上的三件事.mp4', '1-18 作业答案和讲解.mp4', '1-4 编程语言.mp4', '1-11 环境搭建说明.mp3'] file_list = [item.replace(".mp4","") for item in data_list] # 将mp4替换 file_list = [item.replace(".mp4","") for item in data_list if item.endswith(".mp4")] # 将mp4替换 file_list = [item.rsplit(".", maxsplit=1)[0] for item in data_list] # 切分,如果文件中后缀不止有.mp4,则会出现问题 file_list = [item.rsplit(".", maxsplit=1)[0] for item in data_list if item.endswith(".mp4")] # 切分, 添加判断,解决上述问题
2.有一段字符串,将字符串改变为字典格式
data_string = "name=吴佩琦&email=xxx@live.com&gender=男" # 拆分为字典 """ info = { "name": "吴佩琦", "email": "xxx@live.com", "gender": "男" } """ info = {item.split("=")[0]: item.split("=")[1] for item in data_string.split("&")}
3.有一个字典,构成一个字符串,将上面的题逆转过来
result = "&".join(["{}={}".format(k,v) for k, v in info.items()])
4.微信支付,微信对API授权,加密校验过程
info = { 'sign_type': "MD5", 'out_refund_no': "12323", 'appid': 'wx55cca0b94f723dc7', 'mch_id': '1526049054', 'put_trade_no': "ffff", 'nonce_str': "sdfdffd", 'total_fee': 9901, 'refund_fee': 10000 } # 要求:根据键从小到大排序,最终获取如上题的字符串 result = "&".join(["{}={}".format(k, info.get(k)) for k in sorted(info.keys())])
-