自学函数的笔记整理
函数与函数式编程
编程方法:
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()
装饰器自我整理

