1、函数
1.1、函数的用处:复用(一块业务需要反复的实现,每次使用这个业务都需要写一摸一样的代码框架,为了提到代码的简洁性跟提升编写速率,把这种需要使用多次的,相同逻辑业务的代码村放在函数中,如果要使用,直接点用这个函数,传递给这个函数不同之处的变量,即可实现,一段代码多次利用)
1.2、格式:
def 函数名() # 无参函数
代码
def 函数名([c参数,...]) # 有参函数
代码
1.3、函数名命名规则,没有硬性要求,但建议如下:
一个单词,使用小写即可 search()
多个单词不需要大写,使用_分割 get_name()
1.4、定义函数名,相当于栈中定义一个变量。
在函数中定义代码,相当于在堆中定义一个(id value type) 。
所以打印函数名,就会显示函数跟那个堆中的id做绑定,而id是一个十六进制的数。
1.4、验证函数是否可用,调用函数
调用函数模板:函数名()
解释:() 表示获取函数名绑定的 id 地址
用一个案例:封装生成4位二维码函数,作函数的调用
import random def validation_code(): s = '12334567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHKJLZXCVBNM' code = '' for i in range(4): r = random.choice(s) code += r print(code) validation_code()如何知道,我们是否执行了函数中的代码,通过在 函数代码 中加 断点
1.5、带参数函数
def validation_code(n): s = '12334567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHKJLZXCVBNM' code = '' for i in range(n): r = random.choice(s) code += r print(code) validation_code(6)
1.6、多参数函数
def validation_code(a, b): if a == b: print('{}和{}是相等的'.format(a, b)) else: print('{}和{}是不相等的'.format(a, b)) validation_code(7, 7)
1.7 、默认值参数
如果定义一个带有参数的函数,参数是几个,调用的实参就有几个,否则报错
需求:有一个参数非特殊情况,都是固定不变的,只有在特殊的情况才会不一样,由于调用的实参必须跟形参对等,所以这个默认数值每次都的写,如果简化?默认值参数 def 函数名(参数1,参数2,默认值) ,并且可以对默认值进行赋值,取消默认值,使用自定值。如下,我想对比 a b 是不是相等,而且a 是不是大于2
def validation_code(a, b, c=2): if a == b and a > c: print('{}和{}是相等的,而且{}大于{}'.format(a, b, a, c)) else: print('{}和{}是不相等的'.format(a, b)) validation_code(7, 7)
我想对比 a b 是不是相等,而且 a 是不是大于3
def validation_code(a, b, c=2): if a == b and a > c: print('{}和{}是相等的,而且{}大于{}'.format(a, b, a, c)) else: print('{}和{}是不相等的'.format(a, b)) validation_code(7, 7, 3)
注意:默认值参数可以定义多个,但是所有参数在,所有默认值参数之前,否则语法报错。
1.8 形参实参赋值
函数 () 括号中的参数叫做形参
调用函数() 括号中的参数叫做实参
默认不指定,形参1 = 实参1 形参2= 实参2 形参3= 实参3 .....
def validation_code(a, b): print("a=%s" % a) print("b=%s" % b) validation_code(3, 1)
指定,实参1=形参2 实参2=形参1.....
def validation_code(a, b): print("a=%s" % a) print("b=%s" % b) validation_code(b=3, a=1)
1.9 参数类型
参数可以是整型、字符型、浮点型、元组、列表、集合、字典等等
制作一个函数,通过外部传递一个列表,筛选出大于50的数字,并打印此列表
list = [12, 34, 14, 634, 123, 53] def get_list(a): new_list = [i for i in a if i > 50] print(new_list) get_list(list)
制作一个函数,通过外部传递一个列表,筛选出大于 50 的数字,并在原列表中移除
list = [12, 34, 14, 634, 123, 53] def get_list(a): for i in a[::-1]: if i > 50: a.remove(i) print(a)
1.10 可变参数(一个*)
*args **kwargs 这种的带有 * 叫做可变参数,比如 len
可变参数有什么用,怎么用?
1、我们知道,形参跟实参必须对等,但如果形参中使用可变参数,代表实参不管是多少,统一用可变参数代替,可以理解为*后的元素代表是的是一个容器 ,其中可以存放任何元素,并将其存入元组中
list1 = [12, 34, 14, 634, 123, 53] def get_list(*a): print(a) get_list(1, 2) get_list(list1)
2、参数+可变参数 搭配
python 支持按照逗号隔开赋值方法,其中*元素,可以按照格式匹配多数值,并存入列表中。注意a, *b, c = 1, 2, 3, 4, 5这种形式是存入列表中。而可变参数 *args 是转成成元组
a, b, c = 1, 2, 3 print(a) # 1 print(b) # 2 print(c) # 3a, *b, c = 1, 2, 3, 4, 5 print(a) # 1 print(b) # [2, 3, 4] print(c) # 5
对于函数来说也是一样的,函数中也可以使用,参数+可变参数 搭配
list1 = [12, 34, 14, 634, 123, 53] def get_list(a, *b): print(a) print(b) get_list(1, 2, 3, 4) # 按照顺序a = 1 随后使用 *b 去接收 2, 3, 4 get_list(list1) # 由于 list1 赋值给了 a ,导致 *b 接收了 空
1.11 拆包、封包
*a, b, c = 1, 2, 3, 4, 5 print(a) # [1, 2, 3] print(b) # 4 print(c) # 5 a, b, c = (1, 2, 3) print(a) # 1 print(b) # 2 print(c) # 3其中 *a = [1, 2, 3] 为封包,将 1 2 3 元素封装成一个列表,给*a
其中a, b, c = (1, 2, 3) 为拆包,将一个元组中的数据,拆开按照需求一一对应的赋值a, b, *c = (1, 2, 3, 4) print(a) # 1 print(b) # 2 print(c) # [3, 4]拆包、封包 同时进行
案例:求元素的和
def get_list(*sum): print(sum) s = 0 for i in sum: s += i print("元素的和是%s:" % s) get_list(1, 2, 3, 4, 5)
案例:求列表中元素的和
将上述案例,换成列表,会发现报错,主要因为是将 get_list (list1) ,传入的是一个列表,将这个列表整体存在元组中,列表不能进行 + 操作,所以我们要进行干预,对其拆包
python 函数中,定义函数中 def get_list(*sum) ,一个*,代表对传入过来的数据,进行封包成一个元组。
在定义函数中 get_list(*list1) ,*list1 这个 * 代表的是对其拆包,拆的是原数据 list 。注意 * 拆的是列表、元组、集合等
还是上述的案例,我们可以使用get_list(*list1) ,将 list1 拆包成 12, 34, 14, 634, 123, 53 ,然后在通过def get_list(*sum) 封装成元组(12, 34, 14, 634, 123, 53)
list1 = [12, 34, 14, 634, 123, 53] def get_list(*sum): print(sum) # s = 0 for i in sum: s += i print("元素的和是%s" % s) get_list(*list1)
1.12 可变参数(二个*)
通过如下可知,** 代表不是元组了,而是{} ,大括号不是字典就是集合
def show_book(**kwargs): print(kwargs) show_book() # 返回 {} ,代表不是字典就是集合 show_book(1) # 报错 show_book('书') # 报错 show_book('书', 123) # 报错
通过上述,如果是集合,传入一个不重复的元素,就不会被报错,所以另一种可能就是传入的是字典,如下,传入key value,所以 ** 代表是字典 ,必须使用关键字参数赋值
def show_book(**kwargs): print(kwargs) show_book(bookname='书', price=123) # {'bookname': '书', 'price': 123}
既然是字典就可以用字典的形式打印
def show_book(**kwargs): print(kwargs) for k, v in kwargs.items(): # 使用 k ,v 形式获取key 或者 value,使用items遍历打印 print(k, v) show_book(bookname='书', price=123) # {'bookname': '书', 'price': 123}
注意 * 拆的是列表、元组、集合等,** 是拆字典
book = {'bookname': '书', 'price': 123, 'num': 5} def show_book(**kwargs): print(kwargs) for k, v in kwargs.items(): # 使用 k ,v 形式获取key 或者 value,使用items遍历打印 print(k, v) show_book(**book)
python 函数中,定义函数中 def get_list(*sum) ,一个*,代表对传入过来的数据,进行封包成一个元组。** 代表对传入过来的数据,进行封包成一个字典
在定义函数中 get_list(*list1) ,*list1 这个 * 代表的是对其拆包,拆的是原数据 list 。注意 * 拆的是列表、元组、集合等,** 是拆字典
1.13 可变参数 (一个*二个*) 同时存在
同时存在,意义不变,* 就是元组 ,* 就是字典 ,可以传递空,打印空元组,空字典
def show_book(*args, **kwargs): print(args) # 元组 print(kwargs) # 字典 show_book()
可以给一个传递,另一个不传递,则另一个打印空
def show_book(*args, **kwargs): print(args) # 元组 print(kwargs) # 字典 print("\n") show_book('你好', '世界') show_book(bookname='书', price=123)
可以随意组装,调用,结果都是一样的
def show_book(*args, **kwargs): print(args) # 元组 print(kwargs) # 字典 print("\n") show_book('你好', '世界', bookname='书', price=123) book = {'bookname': '书', 'price': 123} show_book('你好', '世界', **book) name = ['你好', '世界'] show_book(*name, bookname='书', price=123) name = ['你好', '世界'] show_book(*name, **book)
*args[] 和**kwargs 统称为不定长参数
1.14 返回值
参数是指,外界往函数里面传递数值,而返回值,代表将函数执行的结果的某一个数值,返回给调用着。
默认格式(返回单一数值):
def get_sum(*args): # total = 12 return total # 定义要返回的元素 x = get_sum(1, 2, 3) # 丁定义让x接收返回的元素
案例1:
def get_sum(*args): total = 0 for i in args: total += i return total x = get_sum(1, 2, 3) print(x)
案例2:返回多个数值,如下可以得知 return min, max 返回的是两个数值,用 result 接收后,是一个元组
def get_maxadmin(numbers): for i in range(0, len(numbers) - 1): for j in range(0, len(numbers) - 1 - i): if numbers[j] > numbers[j + 1]: numbers[j], numbers[j + 1] = numbers[j + 1], numbers[j] min = numbers[0] max = numbers[-1] print(numbers) return min, max list1 = [12, 35, 21, 12, 63, 23, 63, 12] result = get_maxadmin(list1) print(result)而我们知道,元组中的数据,可以通过 变量1,变量2 = ( 元素1,元素2) ,进行赋值
进而将代码简写
def get_maxadmin(numbers): for i in range(0, len(numbers) - 1): for j in range(0, len(numbers) - 1 - i): if numbers[j] > numbers[j + 1]: numbers[j], numbers[j + 1] = numbers[j + 1], numbers[j] min = numbers[0] max = numbers[-1] print(numbers) return min, max list1 = [12, 35, 21, 12, 63, 23, 63, 12] a, b = get_maxadmin(list1) print(a) print(b)
返回多个数值的格式为:
def get_sum(*args): a += 1 b += 1 return a, b c, d = get_sum(1, 2)
1.15 一个函数体调用另一个函数体
案例:自定义登录功能islogin函数体,参数是username, password。自定义图书借阅系统功能boorrow_book函数体,其功能为,先通过islogin函数体正常登录,则可以图书借阅。
思路:通过定义boorrow_book函数体,先让用户输入账户、密码,后调用islogin函数体判断是不是为真,如果为真,则打印可以借阅。
def islogin(username, password): if username == 'admin' and password == '123456': print('登录成功') return True else: print('登录失败,请检查用户名密码') return False def boorrow_book(book_name): username = input('输入用户名:') password = input('输入密码:') if islogin(username, password): print('借阅成功{}'.format(book_name)) book_name = '三国' boorrow_book(book_name) # 输入要借阅的书
1.16 全局变量、局部变量
如下,如果要多次借书,每次都需要登录一下,如何实现一次登录,后不需要在登录
改变代码:
islogin = False def login(username, password): if username == 'admin' and password == '123456': print('登录成功') islogin = True return islogin else: print('登录失败,请检查用户名密码') return False def boorrow_book(book_name): if islogin: print('借阅成功{}'.format(book_name)) else: username = input('输入用户名:') password = input('输入密码:') status = login(username, password) if status: print('借阅成功{}'.format(book_name)) while True: book_name = input('请输入要借阅的书:') boorrow_book(book_name) # 输入要借阅的书
思考:登录成功后,已经通过 islogin = True 修改了 islogin 数值,怎么还是需要重新登录。添加print(islogin) ,在每次循环的时候打印islogin 数值,会发现,每次循环都是False , 说名什么,在函数体中,变量为局部变量,在函数体外的变量,为全局变量,局部变量无法修改全局变量。函数体只有读全局变量的权限,没有修改的权限 。如果全局变量、局部变量都定义了一个变量,则执行局部变量
如何修改全局变量:函数体可以通过 global 命令修改全局变量
格式:在函数体中,先执行 global 全局变量
islogin = False def login(username, password): if username == 'admin' and password == '123456': print('登录成功') global islogin islogin = True return islogin else: print('登录失败,请检查用户名密码') return False def boorrow_book(book_name): if islogin: print('借阅成功{}'.format(book_name)) else: username = input('输入用户名:') password = input('输入密码:') status = login(username, password) if status: print('借阅成功{}'.format(book_name)) while True: print(islogin) book_name = input('请输入要借阅的书:') boorrow_book(book_name) # 输入要借阅的书
( 执行: 局部变量 > 全局变量 权限:默认全局变量只能读,不能改 。 全局变量:函数体可以通过 global 命令修改全局变量)
1.17 案例停车场计费
停车计费系统:
进入停车场记录进入时间,如果出去则记录出去的时间,停车的时间:出去 - 进入时间
停车长数据结构:
[ { ’车牌‘ : [ 进入时间 , 0 ] } , { ’车牌‘ : [ 进入时间 , 出去时间 ] } , ........ ]
计费规则: 15 分钟 1块 1 个小时 4 块知识点:使用 for in 循环遍历字典,取出的是 key 数值。time 取出的是时间戳
import random car_park = [] def enter(): print("-----环境来到停车场-----") while True: a = int(input("请输入要进入还是退出系统,1为进入,2为退出:")) if a == 1: number = input('您要从停车场进来,输入车牌号:') car = {} car[number] = [0] car_park.append(car) print("此车已进入") elif a == 2: break else: print("请输入1或者2,重新输入") print("当前一共有{}多少车辆".format(car_park)) def go_out(): print("-----您要从停车场出去------") number = input('输入车牌号:') for car in car_park: print(car) if number in car: time = random.randint(0, 24) time_record = car.get(number) time_record.append(time) total = time*4 print("{}车已经出场,信息是{},停车{},花费{}".format(number, car, time, total)) break else: print("此车未进入场") enter() print("\n") go_out()
1.18 多个return
一个函数中,同级别的只能有一个return,遇到第一个 return 后退出函数,return后的代码不会执行,所以 return 可以实现终止和退出循环功能
def creaate_muns(): print("1") return 1 print("2") return 2 print("3") return 3 a = creaate_muns() print(a)
一个函数中,不同级别的可以写多个return
def creaate_muns(i): if i == 'a': return 1 elif i == 'b': return 2 a = creaate_muns('a') print(a)
1.19、缺省参数
函数调用是,缺省参数的值如果没有传入,则取默认值
def printinfo(name, age=35): print(name, age) printinfo(name="nihao") # nihao 35 printinfo(age=9, name="nihao") # nihao 9 printinfo(age=10) # 报错
1.20、可变类型、不可变类型
1、所谓可变类型与不可变是指,数据能够直接进行修改,叫可变。不能修改叫不可变
2、可变类型(修改数据,内存地址不会发生变化),列表、字典、集合。理解为移除一个列表中的元素,这个列表对应的堆中,会将对应的堆下得到value数值进行改动,不会从新生成一个新的id、value
3、不可变(修改数据,内存地址发生变化),数字、字符串、元组。理解为 a = ‘123’,字符串移除一个元素,对应的堆下,会重新生成一个新的id,存入你移除后的字符串,然后在赋值给变量a
1.21、引用和函数参数引用
引用:
什么是引用:查看的是当前堆中指定的 id 有多少个变量在与他连接
sys.getrefcount # 使用sys.getrefcount()函数查看引用次数
import sys list1 = [1,2,3,4,5,6] list2 = list1 list3 = list1 print(sys.getrefcount(list1))解释:list1 list2 list 3 都引用了这个堆中的id,所以为3次,而sys.getrefcount函数本身也引用了一次
执行del list3 后是多少,结果是3,因为现在是list1 list2 引用了这个堆中的id,所以为2次,而sys.getrefcount函数本身也引用了一次
import sys list1 = [1,2,3,4,5,6] list2 = list1 list3 = list1 print(sys.getrefcount(list1)) del list3 print(sys.getrefcount(list1))
是先定义的list1 = [1,2,3,4,5,6],如果删除 list1,list2 list3 是依旧存在数据的,因为 list1 是变量,list2 = list1 已经将堆中的id赋值给了list2,结果就是3,因为 list2 list3 引用了这个堆中的id ,而sys.getrefcount函数本身也引用了一次
import sys list1 = [1, 2, 3, 4, 5, 6] list2 = list1 list3 = list1 del list1 print(list2) print(sys.getrefcount(list2))
python 的垃圾回收,如果堆中的id,无任何指针指向(任何变量进行指向赋值),则会触发垃圾回收,进行回收垃圾
函数参数引用:
def test(n1): for i in range(n1): print('------', i) n1 += 1 print(id(n1)) n = 9 test(n) print(n) print(id(n)) n += 1 print(n) print(id(n))通过上述得知n还是9,理解:n = 9 , test(n) 执行后,是将堆中的 9 的 id 给到了 test(n) 中的n,然后执行def test(n1): 将 id 给到了 n1 ,而通过 n1 += 1 后,由于整型是不可变类型,所以9+1=10,10会重新产生一个id,而之前的 n = 9 ,还是指向原来的 id 。之前说过,堆中池子,对于不可变类型,一个value 只有一个id,所以现在n1 = 10 ,n += 1 后 n = 10 , 所以他们的 id 一样
对于可变类型,是可以改变的
a = [1, 2, 3] def list1(l): l.pop() print(l) print(id(l)) list1(a) print(a) print(id(a))
1.22、函数嵌套、闭包
函数是一段可执行的代码,编译后就固化了(加载到内存中),每个函数在内存中只有一份实例,就是一个地址,得到函数的地址,就能执行函数,而函数中,可以存在另一个函数,这种嵌套的结构,就会出现闭包问题。
函数嵌套:
def outer(): print("out") def inner(): print("in") inner() outer()
locals() 在函数中,用来查看内部的局部变量的和对应的堆中的 value ,故返回一个字典,所以通过如下案例,inner()函数中存在两个局部变量。其中 <function outer.<locals>.inner at 0x000001F0BC5AB640> 代表 id = 0x000001F0BC5AB640 在outer函数下,而且是locals代表(局部变量)
def outer(): a = 100 def inner(): b = 200 print("in") print(inner) # <function outer.<locals>.inner at 0x000001F0BC5AB640> result = locals() print(result) # {'a': 100, 'inner': <function outer.<locals>.inner at 0x000001F0BC5AB640>} outer()
1、函数中在嵌套一个函数,被嵌套的函数里 (成为内部),是可以使用外部(上一层的函数)变量,但不能修改,类似全局跟局部变量。
2、而 global 是修改全局变量的,并不适用于这种,这种函数嵌套函数需要用nonlocal。
def outer(): a = 100 c = 200 def inner(): b = 200 b += a nonlocal c c = 20 print("in", b) # in 300 print(a) # 100 print(c) # 200 inner() print(c) # 20 outer()
3、注意nonlocal修改的是你上一层函数的变量。
def outer(): a = 1 def inner(): a = 2 def iiner(): nonlocal a a = 3 print("3层a", a) iiner() print("2层a", a) inner() print("1层a", a) outer()
4、golabl 可以适用于任何层级的函数嵌套中,比如函数1嵌套函数2,函数2嵌套函数3,在函数3中使用golabl可以修改全局变量,但注意在函数3中不要起全局变量的名字,否则golabl修改的是变量
a = 100 def outer(): a = 200 def inner(): global a a -= 50 print("内部", a) print(a) inner() outer() print(a)
闭包:
闭包需要满足一下条件才称之为闭包,闭包就是函数中,声明一个的内部函数,而这个内部函数必须先引出到函数体外进行操作后,在由函数执行这个,内部函数。所以需要满足。因为后续装饰器就这种需求,闭包没什么太大的意义
1、有嵌套函数
2、内部函数引用的外部函数的变量
3、返回值是内部函数
def outer(n): a = 10 def inner(): # 嵌套函数,条件1 b = a + n # 使用了外部函数的a,条件2 print('内部函数:', b) return inner # 返回值是内部函数,条件3 r = outer(5) # r 接收的是 outer 函数的 return ,也就是 return inner,而inner代表的inner函数的地址,所以 r 是 inner 函数的地址 print(r) # 返回的的是inner的地址 <function outer.<locals>.inner at 0x000002BFB6D0B640> r() # 既然r 是 inner 函数的地址,所以直接执行 r 函数,就是调用def inner(),他们都是连接一个内存地址解释:上述可以实现,内部函数 outer,不在内部调用 inner(),在外部用r() 调用 ,因为inner() 和 r() 都是同一个地址
其中如下可以简写
r = outer(5) r() # 写成 outer(5)()
1.23、装饰器
搭配闭包使用,装饰器让开发效率增加。可以理解为,我有一些代码,无任何问题,现在由需求,需要在这个代码上进行增加功能。但是由于之前代码无问题,所以不想直接在原有的代码上修改,这些原有的代码,就可以做成闭包,将函数中的函数拿出来,在外部赋值调用,这些代码,不对原有的代码修改。函数的代码是拿出来了,但是如何让他跟我后写的函数进行结合,使用装饰器。
简单的装饰器:
# 定义装饰器 def decorater(func): def wrapper(): func() print("刷漆") print("装修") return wrapper @decorater def house(): print("毛坯房") @decorater def house2(): print("毛坯房2") house() house2()解释:有一个装饰器代码,你想对那些函数,跟装饰器中的代码进行合并操作。如上,要对house house2 做 decorater 装修操作,如何实现?
简单的装饰器解析:
不执行 house() 发现执行了decorater() 函数中的内容,按道理,除非是执行decorater(),否则只是将函数def decorater(func):加到内存中。既然执行了,没有decorater(),说明是@decorater就是执行调用的
# 定义装饰器 def decorater(func): print('-----------1') def wrapper(): func() print("刷漆") print("装修") print('-----------2') return wrapper @decorater def house(): print("毛坯房")我们知道了@decorater就是decorater()的作用
# 定义装饰器 def decorater(func): print('-----------1') def wrapper(): func() print("刷漆") print("装修") print('-----------2') return wrapper @decorater def house(): print("毛坯房") house()
简单的装饰器解析流程:
1、函数从上倒下,先将 def decorater(func): def wrapper(): 加载到内存中
2、执行 @decorater , 就相当于执行了decorater(),但是函数是def decorater(func):带有func的参数,于是将@decorater下的 def house(): ,也就是house函数的地址,赋值给了func。所以现在是 func = house 地址
3、紧接着执行 def decorater(func): 函数,打印 print('-----------1') print('-----------2'),在执行return wrapper ,也就是返回wrapper 的地址,返回给谁呢?@decorater也没接收,装饰器返回给函数house ,也就是将wrapper 的地址赋值给了house函数的。所以其实 @decorater 等价于 house = decorater(house)
4、执行house,由于上一步将wrapper 的地址赋值给了house函数的,所以你现在执行的house是执行的 wrapper函数,进入wrapper函数,先执行一次func()函数
5、记得在第二步的时候,func = house 地址,所以加一个(),其实就是执行的是原house()函数,所以打印 print("毛坯房")
6、紧接着执行如下
def wrapper(): print("刷漆") print("装修")
装饰器的用途:
1、可以监控谁调用了这个函数,在装饰器中记录
2、函数执行时间统计,比如这个函数执行了多久,装饰器执行前跟执行后的差值
3、执行函数前的准备、清理、权限校验、
4、缓存,将日志缓存到redis、monago
带参数的装饰器:
如果被修饰的函数 house ()有参数,func () 必须也要添加参数,因为 func = house 地址。而由于house = wrapper 地址 ,所以 wrapper 也要添加参数
# 定义装饰器 def decorater(func): print('-----------1') def wrapper(address): func(address) print("刷漆") print("装修") print('-----------2') return wrapper @decorater # house = decorater(house) def house(address): print("房子的地址是{},是一个毛坯".format(address)) house('beijing')
如果存在多个参数呢?使用可变参数
# 定义装饰器 def decorater(func): print('-----------1') def wrapper(*args): func(*args) print("刷漆") print("装修") print('-----------2') return wrapper @decorater # house = decorater(house) def house(address): print("房子的地址是{},是一个毛坯".format(address)) @decorater def dahouse(address, area): print("房子的地址是{},是一个毛坯,建筑面积{}".format(address, area)) house('beijing') dahouse('beijing', 123)
那如果一个函数还有关键字参数?key:value,可变参数(二个*),所以万能模板
# 定义装饰器 def decorater(func): print('-----------1') def wrapper(*args, **kwargs): func(*args, **kwargs) print("刷漆") print("装修") print('-----------2') return wrapper @decorater # house = decorater(house) def house(address): print("房子的地址是{},是一个毛坯".format(address)) @decorater def dahouse(address, area, a=100): print("房子的地址是{},是一个毛坯,建筑面积{},a的数值{}".format(address, area, a)) house('beijing') dahouse('beijing', 123)
带返回值的装饰器
# 定义装饰器 def decorater(func): def wrapper(*args, **kwargs): r = func(*args, **kwargs) print('预计装修费用:{}元'.format(r)) print("刷漆") print("装修") return wrapper @decorater def house(): print("我一个毛坯") return 50000 house()
注意: 此时的r = house(),是 r = wrapper ,所以没有返回数值
# 定义装饰器 def decorater(func): def wrapper(*args, **kwargs): r = func(*args, **kwargs) print('预计装修费用:{}元'.format(r)) print("刷漆") print("装修") return wrapper @decorater def house(): print("我一个毛坯") return 50000 r = house() print(r)# 定义装饰器 def decorater(func): def wrapper(*args, **kwargs): r = func(*args, **kwargs) print('预计装修费用:{}元'.format(r)) print("刷漆") print("装修") return 10000 return wrapper @decorater def house(): print("我一个毛坯") return 50000 r = house() print(r)
装饰器添加参数
# 定义装饰器 def decorater(func): print('-------1-------') def wrapper(action): print('-------3-------') def do_action(action): if func < 22 return action print('-------4-------') return 10000 print('-------2-------') return wrapper @decorater(23) def house(): return 50000
执行流程:
1、执行 @decorater(23) ,23 赋值给 func,随后打印print('-------1-------') print('-------2-------') return wrapper 将 warpper 的地址返回给谁呢?
2、此时的 return wrapper 返回地址,其实是继续调用wrapper() 函数,具体为什么这么写的,应该是底层写好的。随后执行def wrapper(action),而 action 参数是,@decorater(23)下的house对应的堆的地址,随后执行print('-------3-------') ,加载def do_action(): 打印 print('-------4-------')
3、紧接着执行 return do_action ,然后将do_action的地址传递给了 house()。其中do_action (action): 下的 if func < 22 可以使用最外层的 def decorater(func):的func
总结:@decorater(23) 如何带参数,就会多了一轮调用
1.24、递归函数
反复调用自身函数,就是递归函数
要求:
1、必须有出口,否则会死循环
2、每次递归,就会向者出口靠近
def a(): print('------a-------') a() a()# 执行后,会反反复的打印------a-------,在n次数后,python 将会给你停止,因为已经触发最大的递归深度
案例:打印 1-10
# 打印 1-10 def test(i): if i == 10: print('10') else: print(i) i += 1 test(i) test(1)
案例:实现 1..10 相加之和
def test1(i): if i == 10: return 10 else: return i + test1(i + 1) r = test1(1) print(r) # 55
1.25、匿名函数
用 lambda 关键词能创建小型的函数,这个函数叫匿名函数,省略了def 函数名
格式:lamdba 参数列表 运算表达式
注意,匿名函数需要接收一下,为什么?因为函数用 函数() 就可以调用,但是匿名函数式省了函数名,那我怎么调用并获取返回数值
def test(a): return a + 1 可以写成 r = lambda a: a + 1def test(a): return a + 1 result = test(5) print(result) # 6 r = lambda a: a + 1 result = r(5) print(result) # 6---------------------------------------------------------
def test(a): return a + 1 r = lambda x, y: x + y result = r(1, 2) print(result) # 6
场合:
作为参数使用,函数的参数能不能是一个函数
def test(): print('----------test---------') def func(a, f): print('------>', a) f() func(5, test) # 传递函数的名,就相当于传递函数的地址,所以 test 就是堆中的地址,传递给形参f,也就是f 等于test 的地址,执行f(),就是执行了test()
匿名函数作为参数使用
def func(a, f): print('------>', a) r = f(a) print("r", r) # 25 func(5, lambda x: x ** 2)a = 5 f = lambda x: x ** 2 然后执行r = f(a) ,也就是r = lambda 5: 5 ** 2 ,也就是5^2,r = 25
1.26、高阶函数
函数对应的数据类型是 function ,可以把它当作是一个复杂的数据类型。既然同样都是一个数据类型,我们就可以把它当作数字或者字符串来处理。
既然变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,同样,我们还可以把一个函数当做另一个函数的返回值。这样函数的使用方式我们叫做高阶函数。
python提供的系统的高阶函数:sorted函数 filter类 map类 reducec函数 max min
max 用法:
m = max(5, 9) print(m) m = max([2, 4, 6]) print(m) list1 = [('tom', 19), ('tony', 20), ('lily', 17),('daniel', 22)] m = max(list1) print(m) # 返回的是('tony', 20) ,是因为max是按照一个元组中,整体的字符串之和做比较,怎么按年龄?需要key,是一个函数list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)] m = max(list1, key=lambda x: x[1]) print(m) # 返回的是('daniel', 22),其中lambda x,将每一个元组传递给形参x,返回x[1], 也就是a = ('tom', 19) print(a[1]),取下标是1的元组数据,然后在给到max进行排序大小.所以key是一个排序的依据list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)] m = min(list1, key=lambda x: x[1]) print(m) # ('lily', 17)
sorted 用法:
list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)] s = sorted(list1, key=lambda x: x[1]) print(s) # [('lily', 17), ('tom', 19), ('tony', 20), ('daniel', 22)]list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)] s = sorted(list1, key=lambda x: x[1], reverse=True) print(s) # [('daniel', 22), ('tony', 20), ('tom', 19), ('lily', 17)]
filer 过滤:filter 返回的数值是布尔类型
找到年龄大约20岁的
list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)] rr = filter(lambda x:x[1] > 20 ,list1) # 只有x[1] > 20的元组,返回True,才会使用 print(rr) # <filter object at 0x000001950AA67610> ,返回的是一个迭代器,需要强转成list,才会显示 rr = filter(lambda x: x[1] > 20, list1) print(list(rr)) # [('daniel', 22)]等价于
list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)] list2 = [] for i in list1: if i[1] > 20: list2.append(i) print(list2)
map 函数:将某一项数值映射出来,也就是提取出来,返回的是一个map对象,也是迭代器,计算函数使用的次数
list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)] ma = map(lambda x: x + 1, list1) print(ma) # <map object at 0x000001CEF4F47610> print(list(ma)) # 报错,can only concatenate tuple (not "int") to tuple这句话的意思是,提取x[1]的数值,然后对其+1的操作
ma = map(lambda x: x[1] + 1, list1) print(list(ma)) # [20, 21, 18, 23]提取列表的名字,并进行首字母大写(title 将每个单词首字母大写)
list1 = [('tom', 19), ('tony', 20), ('lily', 17), ('daniel', 22)] ma = map(lambda x: x[0].title(), list1) print(list(ma)) # ['Tom', 'Tony', 'Lily', 'Daniel']
reduce 函数:非系统的,必须导入functools,类似计算
from functools import reduce
取出 1 、2 ,分别赋值给x y ,然后通过 x + y 的数值,在赋值给x,然后将 2 后的 3 取出,赋值给 y,在进行x + y ,获取的数值,在赋值给 x
from functools import reduce r = reduce(lambda x, y: x + y, [1, 2, 3, 4, 5]) print(r) # ((((1+2)+3)+4)+5) 等于15
zip函数:
zip() 函数是python内置函数之一,可以将多个序列(列表,元组,字典,字符串以及range()区间构成的列表)压缩成一个zip对象,就是将这些序列中对应的位置元素重新组合生成一个个新的元组
zip() 函数的语法格式为:
zip(iterable, ...)
其中 iterable,… 表示多个列表、元组、字典、集合、字符串,甚至还可以为 range() 区间。
test_list = [1,2,3]
test_tuple = (1,2,3)
# 返回的结果是对象
print('===object===>": ',zip(test_list,test_tuple))
#使用列表推导式转成列表
print('===list===>": ',[i for i in zip(test_list,test_tuple)])
#直接转成列表
print(list(list(zip(test_list,test_tuple))))
# 长短不一致,以短的一方为主
test_str = 'python'
test_str1= 'java'
test_dir = {'name':'jibu','age':30}
test_dir1 = {'name':'jibu','age':30}
#字符串压缩
print('===str===>: ',list(zip(test_str,test_str1)))
#这样好像没啥意义
print('===dir===>: ',list(zip(test_dir,test_dir1)))
#可以获取字典的key
print('===dir===>: ',list(zip(test_dir)))
结果
===str===>: [('p', 'j'), ('y', 'a'), ('t', 'v'), ('h', 'a')]
===dir===>: [('name', 'name'), ('age', 'age')]
===dir===>: [('name',), ('age',)]
应用场景
先需要将A,B两个列表转换成字典
A = ["a", "b", "c", "d"]
B = [1, 2, 3, 4]
result = dict(zip(A,B))
print(result)
结果
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
2、time 关键字
import time s = time.time() # 注意 time.time() 返回的时间是时间戳 print(s)
s = time.time() print(s) time.sleep(3) # 执行 time.sleep(3) 程序会卡住 3 s e = time.time() # 等 3 s 后在执行 time.time() ,对比 s 和 e 的时间戳 ,差 3 s print(e)
s = time.time() print(s) time.sleep(3) e = time.time() print(e) print(e -s) # 通过相减就可以获取 time 的时间差(s)