自学函数的笔记整理
函数与函数式编程
编程方法:
1、面向对象 -->类 -->class(关键字)
2、面向过程 -->过程 -->def(关键字)
3、函数式编程 -->函数 -->def(关键字)
python:非纯函数式编程,也是面向对象的(最火)
定义函数和定义过程的区别:过程即为没有返回值的函数
1 # 定义函数 2 def func1(): 3 print('in the func1') 4 return 0 5 # 定义过程 6 def func2(): 7 print('in the func2') 8 9 x = func1() # x接收返回值0 10 y = func2() # y接收返回值空(python中给出了隐式返回值None) 11 print(x, y) # 0 None
1 def test(x): 2 ''' 3 文档描述 4 :param x: 5 :return: 6 ''' 7 # 函数体(逻辑) 8 x += 1 9 # 定义返回值,终止函数的运行 10 return x
1 import time 2 def test(): 3 ''' 4 文档描述 5 :param x: 6 :return: 7 ''' 8 # 函数体(逻辑) 9 time_format = '%Y-%m-%d %X' # X:时分秒 10 time_current = time.strftime(time_format) 11 # 定义返回值,终止函数的运行 12 return time_current 13 time_current = test() 14 print(time_current) 15 # 2019-09-11 19:16:10
1 #!/user/bin/env python 2 #-*- coding:utf-8 -*- 3 #@Website:智汇部落 4 #@Time:2018-11-02 5 _Author_ = "Uson" 6 7 import time 8 def com(): 9 '''description''' 10 # time_format = "%y-%m-%d %x" # 注意大小写 19-09-11 09/11/19 11 # time_format = "%x" # 09/11/19 12 # time_format = "%y-%m-%d %X" # 19-09-11 21:35:44 13 time_format = "%y-%m-%d %H:%M:%S" # 19-09-11 21:38:27 14 time_str = time.strftime(time_format) 15 # with open("func_file.txt", 'a', encoding='utf-8') as f: 16 f.write("%s:end action1\n" %time_str) 17 18 f = open("func_file.txt",'a+',encoding='utf-8') 19 def func1(): 20 '''description''' 21 f.write("end action1!\n") 22 com() 23 def func2(): 24 '''description''' 25 f.write("end action2!\n") 26 com() 27 28 x = func2() 29 y = func1() 30 f.close() 31 ''' 32 import os 33 os.remove('func_file') 34 '''
优点:1)重复代码-->变函数,实现代码的重用性;2)保持一致性,一改全改; 3)易扩展性(增减)
问题:return可以返回什么样的值?如:return '200',name -->元组形式
1 case1: 返回值个数 = 0:返回None 2 case2: 返回值个数 = 1:返回object 3 case3: 返回值个数 > 0:返回tuple(元组) 4 return还可以返回函数,即其内存地址
返回值的作用:
1、想知道函数的执行结果(譬如:登录操作...)
2、需要根据这个结果接下来执行不同的操作。
有参函数:
1、实参与形参
1)关键字参数与形参顺序无关
2)位置参数(实参)与形参位置一一对应
3)关键字参数不能写在位置参数前面
4)形参不占空间
5)位置参数与关键字参数同时出现,以位置参数的标准来
1 def func(x,y,z): 2 print(x) 3 print(y) 4 print(z) 5 func(3, z=6, y=5) #位置参数只能放在关键字参数前面,关键字参数与形参位置无关 6 #结果:3,5,6 7 func(3,4,z=5) #位置参数3,4与形参一一对应 8 func(x=9,z=8,y=7) #关键字参数与形参位置无关
2、默认参数
1)默认参数特点:函数调用的时候,默认参数非必须传递
2)用途:一键安装,自定义安装默认值;提前固定值,如默认端口号... def com(host, port = 8080)
1 def test(x,y=2): 2 print(x) # 3 3 print(y) # 8 4 test(3, 8) # test(3)、test(1, y=10)
3、参数组
一些情况下,可以少参数(默认参数:隐式),但是不能比形参多
针对实参不固定的情况下,怎么样来定义形参呢?
1)*args:接收N个位置参数,转换成元组的形式(列表前加*)
1 def test1(*args): 2 print(args) # 放元组里 3 test1('Uson',2,3) #位置参数(1) #('Uson', 2, 3) 4 test1(*[2,3]) #忘记它 #直接元组或者列表形式实参 # (2, 3) 5 test1(*(2,3)) #忘记它 #直接元组或者列表形式实参 # (2, 3) 6 test1((2,3)) #忘记它 #直接元组或者列表形式实参 # ((2, 3),) 7 8 def test1_1(x,*args): 9 print(x) # 1 10 print(args) # (2, 3, 4, 5, 7) 11 test1_1(1, 2,3,4,5,7)
2) **kwargs:接收N个关键字参数,转换成字典的形式(字典前加**)
1 def test2(**kwargs): 2 print(kwargs) 3 test2(name='Uson', age=26, sex='w') #关键字参数(2) 4 test2(**{'name':'Uson', 'age':26, 'sex':'w'}) #直接是字典形式实参 5 # {'age': 26, 'sex': 'w', 'name': 'Uson'} 6 # {'name': 'Uson', 'sex': 'w', 'age': 26}
4、混合用:
1)参数组一定要往后放
2)实参位置参数必须在前或必须一一对应
3)给默认参数赋值,可以是位置参数形式
4)默认参数放在形参后面,且不确定参数只能放最后面
1 def test2_2(job,local='shanghai',**kwargs): #默认参数(3)放在形参后面,且不确定参数只能放最后面 2 print(kwargs) 3 print(local) #给默认参数赋值,可以是位置参数形式 4 print(job) 5 # 访问字典 6 # print(kwargs['name']) 7 # print(kwargs['age']) 8 test2_2('python') 9 test2_2('python',name = 'Uson') 10 test2_2('python','hefei',name = 'uson') 11 test2_2('python',name = 'Uson and Cohui',local='luan') 12 test2_2(name='Uson', age=26, sex='M',job='python',local='nanjing') #实参位置参数必须在前或者必须一一对应,其他参数顺序无关 13 # test2_2('python', 'hefei', 'Uson') # X 第三个非关键字参数,错误
5、综合性的混合用
1)job,*args:两个都是接收位置参数,且【N个不确定位置参数形参】必须放在【位置参数形参】后面
1 def test3(job,*args,local='shanghai',**kwargs): #默认参数(3)放在形参后面,且不确定参数只能放最后面 2 print(job) 3 print(args) 4 print(local) 5 print(kwargs) 6 test3('生产助理','周六','调休',name='Cohui', age=25, sex='W',local='Sh') 7 #job,*args:两个都是接收位置参数,且N个不确定位置参数形参必须放在位置参数形参后面 8 9 def test3(job,local='shanghai',*args, **kwargs): 10 print(job) 11 print(args) 12 print(local) 13 print(kwargs) 14 test3('生产助理','周六','调休',name='Cohui', age=25, sex='W',local='Sh') 15 # 报错 16 # TypeError: test3() got multiple values for argument 'local' 17 18 def test3(job, local='shanghai', *args, **kwargs): 19 print(job) 20 print(args) 21 print(local) 22 print(kwargs) 23 test3('生产助理', local='Sh', *['周六','调休'],name='Cohui', age=25, sex='W') # 报错 24 # TypeError: test3() got multiple values for argument 'local' 25 26 def test3(job, local='shanghai', *args, **kwargs): 27 print(job) 28 print(args) 29 print(local) 30 print(kwargs) 31 test3('生产助理', local='Sh', name='Cohui', age=25, sex='W') # *args放在了默认参数后面,只能不传位置参数组实参
6、拆包(调用函数传递实参时,先对元组、字典进行拆包A、B)
局部变量:仅在函数里生效,如果局部变量该全局变量,必须在函数内声明:gloabl 全局变量名
注意:局部变量中不可轻易用global,后果很严重
必知:字符串、数字类、元组这类,在局部变量里修改,全局不会生效,但是:列表、字典、集合类。。。均可在局部里改全局的(换言之,他们没有局部和全局之分)
在局部变量(同名时)的子程序内,局部变量起作用,其他地方,全局变量起作用
PS:如果是不可变类型,局部变量里,会用一个同样的变量名指向全局变量结果而已,跟局部变量没有关系===》只是引用;
如果是可变类型,且是+=类型(非直接=赋值),直接修改数据;如果是等号引用,则不修改,仅临时指向;
附加:所有的等号赋值都是引用。
实际,num+=num并不等于num=num+num:如果是数字类,得到的结果是一样的。如果是列表可变类型,num=num+num只是引用而已,用新的变量名num指向等号右边的结果而已,而非修改全局变量值,如下图:
1 # 示例1 2 website = 'Cohui.top' 3 def test4(website): 4 website = "aka.edu" #局部变量 5 print("our site is: %s" %website) # aka.edu 6 test4(website) 7 print("site is:",website) # Cohui.top 8 9 # 示例2 10 website = 'Cohui.top' 11 def test4(name): 12 global website #局部变量全局化 13 print(name) # alex li 14 name = 'Uson' 15 print(name) # Uson 16 website = "aka.edu" #局部变量 17 print("our site is: %s" %website) # aka.edu 18 name = 'alex li' 19 test4(name) 20 print(name) # alex li 21 print("site is:",website) # aka.edu 22 23 # 示例3 24 names = ['Uosn', 'Alex'] 25 def change_name(): 26 names[1] = '精角大王' # 列表改全局 27 print('inside func:', names) 28 change_name() 29 print(names) 30 # inside func: ['Uosn', '精角大王'] 31 # ['Uosn', '精角大王']
递归:自己调自己
特性:1)必须有明确的结束条件;
2)每次进入更深一层的递归时,问题规模相比上一次的递归都应有所减少;
3)递归的效率不高,层次过多,导致栈溢出
1 #!/user/bin/env python 2 #-*- coding:utf-8 -*- 3 #@Website:智汇部落 4 #@Time:2018-11-03 5 _Author_ = "Uson" 6 7 # 非递归函数 8 def calc(n): 9 print(n) # 50 10 if int(n/2) > 0: 11 return (int(n/2)) #n = 25,跳出循环,未打印 12 print("递归结束后的n值:",n) # 未执行 13 calc(50) 14 # 结果: 15 # 50 16 17 # 递归函数 18 def calc_n(n): 19 print("n:",n) 20 if int(n/2) > 0: 21 return calc_n(int(n/2)) 22 print("递归结束后的n值:",n) 23 calc_n(50) 24 ''' 25 n: 50 26 n: 25 27 n: 12 28 n: 6 29 n: 3 30 n: 1 31 递归结束后的n值: 1 32 '''
高阶函数:一个函数可以接收另一个函数作为参数(即把另一个函数名作为参数传进来)
1 def add(a, b, f): 2 return f(a)+f(b) 3 res = add(-7, 8, abs) # abs绝对值函数 4 print(res) # |-7|+|8| = 15
函数拓展:
1)eval() 函数用来执行一个字符串表达式,并返回表达式的值。
2)eval()函数很强大,可以直接将你所运行的代码进行python执行:
比如说print(eval("1+2"))可以得到结果3;
也可以:如果你的字符串直接是字典的形式,转成字典(输入端的字符串转成字典);
还可以:进行变量的传递eval("{'age':age}",{"age":1822})
1 print(eval( '3 * 7' )) # 21 2 print(eval('pow(2,2)')) # 4 3 4 print(eval("{'name':'linux','age':27}")) # {'name': 'linux', 'age': 27} 5 print(eval("{'name':'linux','age':age}",{"age":1822})) # {'name': 'linux', 'age': 1822}
参考:https://www.cnblogs.com/alex3714/articles/5740985.html
匿名函数
用法:
# 又一批大一堆的lambda # filter(function, iterable) 过滤出想要的数据(过滤大于5的数字) # lambda与filter结合 res = filter(lambda n: n > 5, range(10)) # range,迭代器,lambda通常结合filter用,不单独用 for i in res: print(i) # 6,7,8,9 lambda与map结合,堆传入的每一个值进行处理,变成列表 # map(f, list) f依次作用在list的每个元素 # map()函数不改变原有的list,而返回一个新的list # 用法参考:CMDB示例(New)\AutoCmdb\web\service\asset.py for fun in [lambda x, i=i:i*2 for i in range(10)]: print(fun(2)) for fun in [lambda i=i:i*2 for i in range(10)]: print(fun()) # 0,2,4,6,8,...,18 res2 = map(lambda n: n*n, range(10)) for i in res2: print(i) # lambda与reduce结合 import functools res3 = functools.reduce(lambda x,y: x+y, range(10)) print("res3>>", res3) # 45 res4 = functools.reduce(lambda x,y: x*y, range(1, 10)) print("res3>>", res4) # 362880 乘阶 c = [1, 2, 3, 4] d = ['a', 'b', 'c', 'd','e'] for i in map(lambda *row:list(row), c, d): # 多个位置参数:1,'a' -> [1, ’a'] print(i) ''' [1, 'a'] [2, 'b'] [3, 'c'] [4, 'd'] '''
# 匿名函数的使用 cla = lambda n: n > 5 print(cla(5)) # False cla2 = lambda n: n*3 print(cla2(5)) # 15
# 匿名函数的使用,匿名函数,用完就释放:匿名函数处理不了for循环等复杂操作,只能处理简单的三元运算等 # 三元运算 cal = lambda n: 3 if n < 4 else n print(cal(2)) # 3 def sayhi(n): print(n) sayhi(5) # 变匿名函数 (lambda n: print(n))(5) # 5 # 或 num = lambda n: print(n) num(5) # 5 cla = lambda n: n > 5 print(cla(5)) # False cla2 = lambda n: n*3 print(cla2(5)) # 15
装饰器
装饰器详解
(1)定义:本质是函数
(2)功能:装饰其他函数,为其他函数添加附加功能
(3)原则:1)不能修改被装饰函数的原代码;2)不能修改被装饰函数的调用方式
实现装饰器的知识储备:
(1)函数即“变量”:
1)test(函数名) = ‘函数体’(即一大堆的字符串)
2)函数的定义只要在其调用之前声明,代码都是可以执行的。
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # Author:Uson 4 def fun(): 5 print('我是func') 6 bar() # bar函数只要在fun()执行之前(或bar调用之前)声明即可 7 def bar(): # bar函数的定义 8 print("我是bar") 9 fun() 10 # 我是func 11 # 我是bar
3)变量(或函数)在python中的回收机制及图解:
python的内存回收机制是其解释器做的:(1)自动回收:一是,用了一个引用计数的方式,当x=1,引用计数会加1,y=x,引用计数变成了2,只有当x,y都不在了,1这个值就会被回收,清除1;函数即‘变量’,同理。二是,程序运行结束,自动回收(2)主动回收:del 删除变量或者函数名(门牌号),del没有删除内存地址之意,而是把‘门牌号’(变量名)摘了,定时刷新时发现,1没有了引用,才会将其删除。(3)匿名函数没有函数名,立即回收,赋值给calc变量名(有了门牌号),就不会被立即回收,只要引用的变量名还在,且程序仍在运行,就不会被回收。
1 calc = lambda x:x*3 2 print(calc(3)) # 9
匿名函数当做实参传递:
匿名函数的应用实例:
python3 input得到的是字符串,需要通过eval函数转成可执行的表达式(如3+4=“3+4”)
python2 input得到的不是字符串,而是可执行的表达式(如3+4=7)
静态语言:C C++ 先确定功能才会执行
动态语言:Python 在运行的一刹那,才确定其功能
(2)高阶函数
2个方式必须满足其中的一个条件:
1)把一个函数名当做实参传给另一个函数(在不修改被装饰函数原代码的情况下,为其添加新功能)
2)返回值中包含函数名(不修改函数的调用方式) def foo(func):return func
1 import time 2 # 原代码(也是被装饰函数) 3 def bar(): 4 print("我是bar") 5 # 装饰函数 6 def deco(func): # func:bar的内存地址 (高阶函数) 7 start_time = time.time() 8 func() # bar函数的执行 9 stop_time = time.time() 10 print("The bar run time is %s" %(stop_time-start_time)) 11 return func # 返回bar的内存地址 12 # t = test(bar) # t接收bar的内存地址 13 # t() # 调用bar函数 14 # 等同于: 15 bar = deco(bar) 16 bar() # 被装饰函数的调用方式 17 # 结果: 虽然没有修改被装饰函数的原代码,也没有修改被装饰函数的调用方式,但是多调用了一次bar函数,所以称不上装饰器 18 # 我是bar 19 # The bar run time is 0.0 20 # 我是bar
(3)嵌套函数
在一个函数的定义里面,再定义 ==>*args, **kwargs拆包之意
1 x=0 2 def grandpa(): 3 x=1 4 def dad(): 5 x=2 6 def son(): 7 x=3 8 print(x) 9 son() 10 dad() 11 grandpa()
高阶函数 + 嵌套函数 ===》装饰器
1 #!/usr/bin/env python 2 # Author:USON 3 4 import time 5 def deco(fun): #定义一个嵌套函数 fun = test1 6 def timer(*args, **kwargs): #高阶函数 完善:传递非固定参数,实现通用性*args, **kwargs 7 start_time = time.time() 8 fun(*args, **kwargs) # test1/test2 9 stop_time = time.time() 10 print("the fun run time is %s" %(stop_time-start_time)) 11 return timer 12 @deco #test1 = deco(test1) deco(test1) = timer地址 必须写在被装饰函数的定义上方,读至此,会把下一行函数定义解释到内存 13 def test1(): 14 time.sleep(1) 15 print("in the test1") 16 @deco 17 def test2(name, age): 18 time.sleep(1) 19 print(name, age) 20 #test1 = timer 21 test1() # 执行timer() 22 test2("Uson", 27) # 执行timer("Uson", 27)
装饰器案例剖析
装饰器的应用场景拓展:
1 #!/usr/bin/env python 2 # Author:USON 3 4 #实现的功能:3个网页,index(主页,无权限),home、bbs(登录认证) 5 6 username, password = "Uson", "ys9213" 7 def auth(func): #func = home 8 def warpper(*args, **kwargs): 9 name = input("Username:").strip() 10 pwd = input("Password:").strip() 11 if username == name and password == pwd: 12 print("\033[32;1mValid name\033[0m") 13 res = func(*args, **kwargs) # 返回执行结果1 14 return res # 返回执行结果1 15 else: 16 exit("\033[31;1mInvalid name or password!\033[0m") 17 # print("\033[31;1mInvalid name or password!\033[0m") #两种方式退出 18 # exit() 19 return warpper 20 21 def index(): 22 print("Welcome come to index!") 23 @auth #home=auth(home) home = warpper 24 def home(): 25 print("Welcome come to home!") 26 return "From Home" 27 @auth 28 def bbs(): 29 print("Welcome come to bbs!") 30 index() 31 home() #warpper() 32 #print(home())# 返回执行结果1 = res = home() print(res) 33 bbs()
1 #!/usr/bin/env python 2 # Author:USON 3 4 #实现的功能:3个网页,index(主页,无权限),home(本地file登录权限),bbs(远程ldap认证登录权限) 5 6 username, password = "Uson", "ys9213" 7 username2, password2 = "Us", "ys9213" 8 def auth(auth_type): #auth_type = local 9 #print(auth_type) #auth_type = local 10 def outer(func): #func = home #不传参,定义:只有同级别,传参,定义往下走一级 11 def warpper(*args, **kwargs): 12 name = input("Username:").strip() 13 pwd = input("Password:").strip() 14 if auth_type == "local": 15 if username == name and password == pwd: 16 print("\033[32;1mValid name\033[0m") 17 res = func(*args, **kwargs) 18 print("我是本地登录:",res) 19 else: 20 exit("\033[31;1mInvalid name or password!\033[0m") 21 elif auth_type == "ldap": 22 if username2 == name and password2 == pwd: 23 print("\033[32;1mValid name\033[0m") 24 func(*args, **kwargs) 25 print("我是远程登录!") 26 else: 27 exit("\033[31;1mInvalid name or password!\033[0m") 28 return warpper 29 return outer 30 31 def index(): 32 print("Welcome come to index!") 33 @auth(auth_type = "local") # home=auth((auth_type = "local")(home)) 分解: 34 # outer = auth((auth_type = "local") 35 # 变成 home = outer(home) 36 # 变成 home = warpper 37 # 走下一步 38 def home(): 39 print("Welcome come to home!") 40 return "From Home" 41 @auth(auth_type = "ldap") 42 def bbs(): 43 print("Welcome come to bbs!") 44 index() 45 home() #warpper() --> 开始调用warpper函数 46 bbs()
装饰器自我整理