函数的基本操作

允我心安 提交于 2019-12-05 06:45:52

自学函数的笔记整理

函数与函数式编程

编程方法:

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
结合strftime的应用
 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还可以返回函数,即其内存地址
View Code

返回值的作用:

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)
View Code

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}
View Code

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 第三个非关键字参数,错误
View Code

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放在了默认参数后面,只能不传位置参数组实参
View Code

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', '精角大王']
View Code

递归:自己调自己

特性: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}
eval的强大功能

参考: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
View Code

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()
View Code

高阶函数 + 嵌套函数 ===》装饰器

 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()
案例剖析高潮版

装饰器自我整理

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!