前言
本篇博客整合了以下与函数有关的知识点
函数
函数的简介
# 函数:以功能(完成一件事)为导向,登录,注册,len,一个函数就是一个功能。 随调随用。 # 减少代码的重复性。 # 增强了代码的可读性。
函数的结构与调用
定义一个函数 def len_num(a): return len(a) b=len_num([123,1,2]) print(b) # 结构: #def 关键字,定义函数。 #len_num 函数名:与变量设置相同,具有可描述性。 #函数体 :缩进。函数中尽量不要出现print 函数可以没有return 但没有return返回值就没有意义 # return后面是返回值(len(a)) 在函数中遇到return直接结束函数。 # return 将数据返回给函数的执行者,调用者 len_num()。 # return 返回单个元素 是返回原有数据类型的形式返回 # return 返回多个元素 是以元组的形式返回给函数的执行者。
函数的返回值
# return 将数据返回给函数的执行者,简单来说谁调用返回谁 # return 返回单个元素 是返回原有数据类型的形式返回 # return 返回多个元素 是以元组的形式返回给函数的执行者。
函数的参数
# 写一个函数,只接受两个int的参数,函数的功能是将较大的数返回。 # def compile(a,b): #行参 1.位置参数 2. 默认参数(经常使用的参数) # c = 0 # if a > b: # return c # else: # return c # compile(10,20)#实参 位置参数 关键字参数, # 形参角度: # 1. 位置参数 # 2. 默认参数 (经常使用的参数) # 实参角度: # 1. 位置参数 按照顺序,一一对应 # 2. 关键字参数, 一一对应 # 3. 混合参数:位置参数一定要在关键字参数的前面。
万能参数,仅限关键字参数
# 万能参数: *args, 约定俗称:args, # 函数定义时,*代表聚合。 他将所有的位置参数聚合成一个元组,赋值给了 args。 # 写一个函数:计算你传入函数的所有的数字的和。 # def func(*args): # count = 0 # for i in args: # count += i # return count # print(func(1,2,3,4,5,6,7)) # **kwargs # 函数的定义时: ** 将所有的关键字参数聚合到一个字典中,将这个字典赋值给了kwargs. # 形参角度:仅限关键字参数 (了解) 可以在默认参数前也可以在后面 一定要传参数,不传报错 # 形参角度最终的顺序:位置参数,*args,默认参数,仅限关键字参数,**kwargs # *的魔性用法 # **在函数的调用时,*代表打散。 def func(*args,**kwargs): print(args) # (1,2,3,22,33) print(kwargs) # func(*[1,2,3],*[22,33]) # func(1,2,3,22,33) # func(*'fjskdfsa',*'fkjdsal') # func(1,2,3,22,33) func(**{'name': '太白'},**{'age': 18}) #func(name='太白',age='18')
*的魔性用法。
# *在函数的调用时,*代表打散。 **{'name': '太白'}打散为name='太白' *[1,2,3]打散为1,2,3 # 函数外:处理剩余元素 # a,b,*c = [1,2,3,4,5] # a,*c,b, = [1,2,3,4,5] # a,*c = range(5) # a,*c,b = (1,2,3,4,5,6) # print(a,c,b)
名称空间作用域
# 内置名称空间:python源码给你提供的一些内置的函数,print input # python分为三个空间: # 内置名称空间(builtins.py) # 全局名称空间(当前py文件) # 局部名称空间(函数,函数执行时才开辟) # 加载顺序: # 内置名称空间 ---> 全局名称空间 ----> 局部名称空间(函数执行时) # 取值顺序(就近原则) 单向不可逆 # (从局部找时)局部名称空间 ---> 全局名称空间 ---> 内置名称名称空间 # 作用域: # 两个作用域: # 全局作用域 :内置名称空间 全局名称空间 # 局部作用域:局部名称空间(函数等) # 局部作用域可以引用全局作用域的变量 # 局部作用域不能改变全局变量。 可以使用可以,不能改变 # 注意 python中不可以先引用 后定义
高阶函数
# 就是函数的嵌套 # 例1: def func1(): print('in func1') print(3) def func2(): print('in func2') print(4) func1() print(1) func2() print(2) # in func1 3 1 in func2 4 2 # 例2: def func1(): print('in func1') print(3) def func2(): print('in func2') func1() print(4) print(1) func2() print(2) # 例3: def fun2(): print(2) def fun3(): print(6) print(4) fun3() print(8) print(3) fun2() print(5)
内置函数 globals locals
# 内置函数:globals locals a = 1 b = 2 def func(): name = 'alex' age = 73 print(globals()) # 返回的是字典:字典里面的键值对:全局作用域的所有内容。 print(locals()) # 返回的是字典:字典里面的键值对:当前作用域的所有的内容。 # print(globals()) # 返回的是字典:字典里面的键值对:全局作用域的所有内容。 # print(locals()) # # 返回的是字典:字典里面的键值对:当前作用域的所有的内容。 func()
global nonlocal关键字
# global # 1, 在局部作用域声明一个全局变量 声明后就可以修改全局变量 # nonlocal 存在于双层嵌套中 # 1. 不能够操作全局变量。 # 2. 作用局部作用域:内层函数对外层函数的局部变量进行修改。
函数名的应用
# 函数名是一个特殊的变量。 # 函数名指向的是函数的内存地址,加上()就执行这个函数。 # 3. 函数名可以作为容器类类型的元素。 # 4. 函数名可以作为函数的实参。 # 5. 函数名可以作为函数的返回值。
默认参数的坑
# 陷阱只针对于默认参数是可变的数据类型: # 如果你的默认参数指向的是可变的数据类型,那么你无论调用多少次这个默认参数,都是同一个。 # 本质是闭包 # def func(name,alist=[]): # alist.append(name) # return alist # ret1 = func('alex') # print(ret1,id(ret1)) # ['alex'] # ret2 = func('太白金星') # print(ret2,id(ret2)) # ['太白金星'] # 局部作用域的坑 # 在函数中,如果你定义了一个变量,但是在定义这个变量之前对其引用了,那么解释器认为:语法问题。 # 你应该在使用之前先定义。 # 列题 # count = 1 # def func(): # count += 1 # print(count) # func()
可迭代对象和迭代器
# 可以进行循环更新的一个实实在在值。 # 如何判断一个对象是否是可迭代对象: 利用内置函数:dir()可以查看对象内部方法 # 有__iter__方法的对象,都是可迭代对象。 # print('__iter__' in dir(str)) # 如何判断一个对象是迭代器: 可更新迭代的工具 # 在python中,内部含有'__iter__'方法并且含有'__next__'方法的对象就是迭代器。 # print('__iter__' in dir(str) and '__next__' in dir(str)) # 可迭代对象转化成迭代器: # 利用内置函数iter() # obj = iter(l1) # object.__iter__() # 迭代器可以迭代取值。利用next()进行取值(节省内存)或者转为list 元祖等等取值 # 一个next()取一个值 且会记录位置 # 迭代器一条路走到底,不走回头(记录位置)。 # 取完了再next()会报错(StopIteration) 我们可以用try处理 万能异常(Exception)
while模拟for循环
s = 'gkffdsa;lfkdsk;lafkds;laldgjfd' obj = iter(s) while 1: try: print(next(obj)) except StopIteration: break
可迭代对象与迭代器的对比
可迭代对象与迭代器的对比
- 可迭代对象是一个操作方法比较多,比较直观,存储数据相对少(几百万个对象,8G内存是可以承受的)的一个数据集。
- 当你侧重于对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择。
- 是一个非常节省内存,可以记录取值位置,可以直接通过循环+next方法取值,但是不直观,操作方法比较单一的数据集。
- 当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。
生成器
# return作用 返回值 单个或多个 终止函数 # 结束函数,给函数的执行者返回值(多个值通过元组的形式返回)。 # 将return换为yield就是生成器函数 # 只要函数中出现了yield那么他就不是函数,它是生成器函数。 # 不结束函数,对应着给 next 返回值(多个值通过元组的形式返回)。 会记录位置 def func(): yield 2,4,5 print(11) yield 3 print(22) print(33) yield 4 yield 5 ret = func() # 生成器对象 # print(ret) # print(next(ret)) # print(next(ret)) # print(next(ret)) # yield : 对应next给next返回值
yield from
# yield from 将一个可迭代对象的每一个元素返回给next # yield from 节省代码,提升效率(代替了for循环) # def func(): # l1 = [1, 2, 3] # yield from l1#就是下面的简写 # ''' # yield 1 # yield 2 # yield 3 # ''' # ret = func() # print(next(ret))
出错题
def eat_baozi_gen(): for i in range(1,5): yield f'{i}号包子' print(11) ret1 = eat_baozi_gen() for i in ret1: print(i)
生成器表达式,列表推导式,字典推导式
# 两种构建方式: # 1.循环模式: [变量(加工后的变量) for 变量 in iterable] # print([i**2 for i in range(1, 11)]) # 2.筛选模式: [变量(加工后的变量) for 变量 in iterable if 条件] # print([i**2 for i in range(1, 11)]) # 列表推导式的优缺点: # 优点: # 1, 简单,快捷,装b。 # 缺点: # 2. 可读性不高,不好排错。 # 慎用,不要入迷。 # 生成器表达式: 小括号 # 与列表推导式几乎一模一样。 # 循环模式,筛选模式。 # obj = (i for i in range(1, 11)) # 字典推导式,集合推导式: 两种模式: 循环模式,筛选模式 l1 = ['小潘', '怼怼哥','西门大官人', '小泽ml亚'] # {0: '小潘', 1: '怼怼哥', 2: '西门大官人'} # dic = {} # for index in range(len(l1)): # dic[index] = l1[index] # print(dic) # print({i:l1[i] for i in range(len(l1))})
匿名函数
一句话函数 一般与内战函数结合
# 匿名函数:没有名字的函数 # 匿名函数只能构建简单的函数,一句话函数。 # func2 = lambda 形参: 返回值 # func2 = lambda x,y: x + y
小练习
i改变了指向 func_list = [] for i in range(10): func_list.append(lambda x:x+i) v1 = func_list[0](2) v2 = func_list[5](1) print(v1,v2) func_list = [] for i in range(10): func_list.append(lambda x:x+i) for i in range(0,len(func_list)): result = func_list[i](i) print(result) result = [] for i in range(10): func = lambda : i # 注意:函数不执行,内部代码不会执行。 result.append(func) print(i)#9 print(result) v1 = result[0]() v2 = result[9]() print(v1,v2) def func(num): def inner(): print(num) return inner result = [] for i in range(10): f = func(i) result.append(f) print(i) print(result) v1 = result[0]() v2 = result[9]() print(v1,v2) 如 10.3.9.12 转换规则为二进制: 10 00001010 3 00000011 9 00001001 12 00001100 再将以上二进制拼接起来计算十进制结果:00001010 00000011 00001001 00001100 = ? # IP地址转换为int # 思路IP按照split进行分隔成4个部分,然后每个部分都转换为二进制类型. # 然后将这些二进制进行拼接成一个32位的大的二进制字符串. # 最后将这个二进制数,转换成对应的int类型 def ipToInt(ip_str): # 分隔 ip_list = ip_str.split('.') # 拼接 bin_str = "" # 遍历,然后求出每一个二进制数,(注意切割,舍弃0b),还要把它弄成8位.再相加 for i in ip_list: part = bin(int(i))[2:] # 将part前面补充0 part = part.zfill(8) bin_str += part # 最后将这个二进制数转换为整数 ip_int = int(bin_str, 2) return ip_int v = [lambda :x for x in range(10)] print(v) print(v[0]) print(v[0]()) v = (lambda :x for x in range(10)) print(v) print(next(v)) print(next(v)()) def num(): return [lambda x:i*x for i in range(4)] print([m(2)for m in num()])
内置函数
内置函数 I 了解
# all() any() bytes() callable() chr() complex() divmod() eval() exec() format() frozenset() globals() hash() help() # id() input() int() iter() locals() next() oct() ord() pow() repr() round() # eval 剥去字符串的外衣,返回里面的本质 # s1 = "{1: 'alex'}" # ret = eval(s1) # exec 代码流,过程。 # s3 = ''' # for i in range(3): # print(i) # ''' # exec(s3) # hash:获取一个对象(可哈希对象:int,str,Bool,tuple)的哈希值。 # print(hash(12322)) # help:函数用于查看函数或模块用途的详细说明。 # print(help(list)) # print(help(str.split)) # int:函数用于将一个字符串或数字转换为整型。 # print(int('0100',base=2)) # 将2进制的 0100 转化成十进制。结果为 4 # float:函数用于将整数和字符串转换成浮点数。 # complex:函数用于创建一个值为 real + imag * j 的复数或者转化一个字符串或数为复数。如果第一个参数为字符串,则不需要指定第二个参数。。 # divmod:计算除数与被除数的结果,返回一个包含商和余数的元组(a // b, a % b)。 # round:保留浮点数的小数位数,默认保留整数。 # pow:求x**y次幂。(三个参数为x**y的结果对z取余) # bytes:用于不同编码之间的转化。 # ord 输入字符找该字符编码的位置 # chr 输入位置数字找出其对应的字符 # repr:返回一个对象的string形式(原形毕露)。 # print(repr('{"name":"alex"}')) # print('{"name":"alex"}') # %r 原封不动的写出来 # name = 'taibai' # print('我叫%r'%name)
callable 判断是否可调用
# callable:函数用于检查一个对象是否是可调用的。如果返回True,object仍然可能调用失败; # 但如果返回False,调用对象ojbect绝对不会成功。 # name = 'alex' # def func(): # pass # print(callable(name)) # False # print(callable(func)) # True
bin oct hex进制转换
# bin:将十进制转换成二进制并返回。 # oct:将十进制转化成八进制字符串并返回。 # hex:将十进制转化成十六进制字符串并返回。 # 二进制 to 十进制: int(str,n=10)
all any判断是否全部为真或假
# all 可迭代对象中,全都是True才是True # any 可迭代对象中,有一个True 就是True # print(all([1,2,True,0])) # print211444(any([1,'',0]))
内置函数II 重要
# abs() enumerate() filter() map() max() min() open() range() print() len() list() # dict() str() float() reversed() set() sorted() sum() tuple() type() zip() dir() bytes() #把字符串转换成bytes类型
sep 设定分隔符。
print(1, 2, 3, sep='|')
end去除默认换行
print(1, 2, end=' ')
abs() 获取绝对值
print(abs(-10))
sum() 数字相加求和
# sum() 数字相加求和 会for循环里面元素 必须里面都是由int组成 注意列表 sum(iterable,) print(sum([1, 2, 3, 4], 100))
min max()可以加功能
# min 可以加功能 key 与匿名函数结合 # min 可以加功能 # print(min([22, 11, 45, 2])) # l1 = [(73, 'alex'), (35, '武大'), (18, '太白')] # print(min(l1,key=lambda x: x[0])) # print(min(l1,key=lambda x: x[0])[0]) # 第一步 循环遍历l1 将里面的元素以形参的方式传给匿名函数得到返回值 # 第2步 利用内置函数比较返回值 得到想要的结果,在将传进去的元素返回
reversed() 将一个序列翻转
# reversed() 将一个序列翻转, 返回翻转序列的迭代器 reversed 示例: # l = reversed('123') # l 获取到的是一个生成器 注意字符串转list会分隔 # print(list(l))
sorted排序函数 可以加key
# lst = [{'id': 1, 'name': 'alex', 'age': 18}, # {'id': 2, 'name': 'wusir', 'age': 17}, # {'id': 3, 'name': 'taibai', 'age': 16}, ] # # 按照年龄对学生信息进行排序 # print(sorted(lst, key=lambda e: e['age'])) l = ['班级24','班级15','班级3','班级5','班级25']#,按照数字的顺序从大到小排序,不改变原列表,请以最少代码量实现。(3分) print(sorted(l, key=lambda e: int(e[2:]),reverse=False))
map对元素进行映射
# map(function,iterable) 可以对可迭代对象中的每一个元素进行映射,分别取执行function # 计算列表中每个元素的平方,返回新列表 # lst = [1,2,3,4,5] # def func(s): # return s*s # mp = map(func,lst) # print(mp)#对象 # print(list(mp)) # # 改写成lambda # print(list(map(lambda s:s*s,lst)))
zip() 拉链方法
# zip() 拉链方法。函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组, # 然后返回由这些元祖组成的内容,如果各个迭代器的元素个数不一致,则按照长度最短的返回 # lst1 = [1,2,3] # lst2 = ['a','b','c','d'] # lst3 = (11,12,13,14,15) # for i in zip(lst1,lst2,lst3): # print(i)
filter筛选过滤 返回迭代器
filter筛选过滤 返回迭代器 ls = filter(lambda e:e['age'] > 16,lst)
闭包
定义:
默认参数就是闭包原理
- 闭包是嵌套在函数中的函数。
- 闭包必须是内层函数对外层函数的变量(非全局变量)的引用。
# 引用的变量就是自由变量,自由变量不会随着函数的执行结束之后而消失 # 如何判断判断闭包 # 如果此函数拥有自由变量,那么就可以侧面证明其是否是闭包函数了 # 利用 函数名.__code__.co_freevars 查看函数的自由变量 # 闭包的作用:保存局部信息不被销毁,保证数据的安全性。 # 闭包的应用: # 可以保存一些非全局变量但是不易被销毁、改变的数据。 # 装饰器。
装饰器
开放封闭原则:
装饰器:装饰,装修,房子就可以住,如果装修,不影响你住,而且体验更加,让你生活中增加了很多功能:洗澡,看电视,沙发。 器:工具。 开放封闭原则: 开放:对代码的拓展开放的, 更新地图,加新枪,等等。 封闭:对源码的修改是封闭的。 装饰器:完全遵循开放封闭原则。 装饰器: 在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。 装饰器就是一个函数。
推导见代码
标准版的装饰器;
标准版的装饰器; def wrapper(f): f = zz # 第2步 def inner(*args, **kwargs): # 第5步 ret = f(*args,**kwargs)#第7步 return ret return inner # 第3步 @wrapper # zz=weapper(zz) 第一步 def zz(): # 第4步 此时zz 为 inner pass
带参数的装饰器
def wrapper_out(n,*args,sex="男") def wrapper(f): def inner(*args,**kwargs): ret = f(*args,**kwargs) # 这边执行的是func1() return ret return inner return wrapper def func1(): print("in func1") func = wrapper_out(1) # wrapper函数名 ly = fun(func1) # inner = wrapper(func1) ly() # inner() def wrapper_out(n): def wrapper(f): def inner(*args,**kwargs): if n == "qq": username = input("请输入用户名:").strip() password = input("请输入密码:").strip() with open("qq",encoding="tuf-8") as f1: for line in f1: user,pwd = line.strip().split("|") if username == user and password == pwd: print("登陆成功") ret = f(*args,**kwargs) return ret return False elif n == "yiktok": username = input("请输入用户名:").strip() password = input("请输入密码:").strip() with open("qq",encoding="tuf-8") as f1: for line in f1: user,pwd = line.strip().split("|") if username == user and password == pwd: print("登陆成功") ret = f(*args,**kwargs) return ret return False def wrapper_out(n): def wrapper(f): def inner(*args,**kwargs): username = input("请输入用户名:").strip() password = input("请输入密码:").strip() with open(n,encoding="tuf-8") as f1: for line in f1: user,pwd = line.strip().split("|") if username == user and password == pwd: print("登陆成功") ret = f(*args,**kwargs) return ret return False return inner return wrapper @ wrapper_out("qq") def qq(): print("成功访问qq") qq() # 看到带参数的装饰器分两步执行: @ wrapper_out("腾讯") # 1.执行wrapper_out("腾讯"),把相应的参数传给n,并且得到返回值wrapper函数名 # 2.将@与wrapper结合,得到我们之前熟悉的标准版装饰器,按照装饰器的执行流程执行 @ wrapper_out("qq") def qq(): print("成功访问qq") @ wrapper_out("tiktok") def tiktok(): print("成功访问抖音") qq() tiktok() # 开发思路:增强耦合性
多个装饰器装饰一个函数
def wrapper1(func1): # func1 = f原函数 def inner1(): print('wrapper1 ,before func') # 2 func1() print('wrapper1 ,after func') # 4 return inner1 def wrapper2(func2): # func2 == inner1 def inner2(): print('wrapper2 ,before func') # 1 func2() # inner1 print('wrapper2 ,after func') # 5 return inner2 @wrapper2 # f = wrapper2(f) 里面的f == inner1 外面的f == inner2 @wrapper1 # f = wrapper1(f) 里面的f == func1 外面的f == inner1 先看下面 def f(): print('in f') # 3 f() # inner2() 看外层f
递归
# 官网规定:默认递归的最大深度1000次。 # 如果你递归超过100次还没有解决这个问题,那么执意使用递归,效率很低。 递归比起循环来说更占用内存 # 修改递归的最大深度 # import sys # sys.setrecursionlimit(1000000000) # 递归就是自己调自己 # 递归函数是怎么停下来的?递归3次结束整个函数 # 一个递归函数要想结束,必须在函数内写一个return,并且return的条件必须是一个可达到的条件 # --注意---并不是函数中有return,return的结果就一定能够在调用函数的外层接收到 谁调用最后一个函数返回给谁 # 加上return tet # def func(count): # count += 1 # print(count) # if count == 5 : return 5#这个5其实是返回给下面的func() # ret = func(count)#要想把这个5返回给最外层 所以逐层returt # return ret # 精简版 def func(count): count += 1#这里是代码思路 if count == 5 : return 5#这个5其实是返回给下面的func() return func(count)#精简了上面的过程 # 1.计算阶乘 100! = 100*99*98*97*96....*1 def fin(n): if n ==1 : return n else: return n*fin(n-1) ret = fin(7) print(ret) l2 = [1, 3, 5, ['太白','元宝', 34, [33, 55, [11,33]]], [77, 88],66] # # 错误方法 # for i in l2: # if type(i) == list: # for j in i: # print(j) # else: # print(i) # 递归 # def func(alist): # for i in alist: # if type(i) == list: # func(i) # func(['太白','元宝',34]) # else: # print(i) # func(l2) # 5.三级菜单 可能是n级 # 2.os模块:查看一个文件夹下的所有文件,这个文件夹下面还有文件夹,不能用walk # 3.os模块:计算一个文件夹下所有文件的大小.这个文件夹下面还有文件夹,不能用 walk # 4.计算斐波那契数列 # 找第100个数 # 1.计算阶乘 100! = 100*99*98*97*96....*1
来源:https://www.cnblogs.com/saoqiang/p/12111370.html