07 python函数
函数是结构化编程的核心。
函数可以提高代码的模块化和重复利用率。
1、函数的定义和调用
使用def语句定义函数。
def 函数名([参数1, 参数2, ...]): 函数体
示例:
import random def generate_random(): #定义函数,无参数 for i in range(10): ran = random.randint(1, 20) print(ran) print(generate_random) #打印函数名:<function generate_random at 0x000001F03C2254C0>
generate_random() #调用函数,函数名后必须有小括号,代表引用函数体。
2、函数的参数
- 在def语句中,位于函数名后面的变量称为形参,而调用函数时提供的值称为实参。
2.1、位置参数
- 位置参数:实参和形参数量一致,且一一对应。
- 参数的位置至关重要。
def 函数名(参数1, 参数2, ...): 函数体
示例:
def add(a, b): #a和b是形参。形参可以有多个 sum1 = a + b print('a + b =', sum1) add(1, 3) #1和3是实参。实参要和形参数量一致,且一一对应
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
''' 定义一个登录函数,参数是username、password。 判断参数传过来的值是否正确,如果正确就打印登录成功,否则打印登录失败。 ''' def login(username, password): name = 'admin' pwd = '123456' if name == username and pwd == password: print('登录成功') else: print('登陆失败') login('admin', '123456')
2.2、关键字参数
- 关键字参数:使用名称指定的参数。
- 关键字参数最大的优点在于,可以指定默认值。
- 位置参数和关键字参数可以混合使用,但必须先指定所有的位置参数(位置参数必须在前面),否则解释器将不知道它们是哪个参数(即不知道参数对应的位置)。
- 通常不应混合使用位置参数和关键字参数
def func(a, b, c=6): #混合使用位置参数和关键字参数 print('a = {}, b = {}, c = {}'.format(a, b, c)) func(1, 2) #结果是:a = 1, b = 2, c = 6。位置参数必须传递实参,关键字参数可以使用默认值 func(b=2, a=1) #结果是:a = 1, b = 2, c = 6。关键字参数的位置不重要 func(1, 2, 3) #结果是:a = 1, b = 2, c = 3 func(1, 2, c=3) #结果是:a = 1, b = 2, c = 3。
2.3、收集参数(装包)
- 有时候要允许用户提供任意数量的参数。
- 收集参数:定义函数时使用运算符*实现。
1、单星号(*)
- 单星号收集多余的位置参数,并存放进一个元组中。如果没有多余的位置参数,元组将是一个空元组。
- 单星号不会收集关键字参数。
def func(a, *b, c): print('a = {}, b = {}, c = {}'.format(a, b, c)) func(1, c=2) #结果是:a = 1, b = (), c = 2。要使用关键字参数指定后面的参数 func(1, 2, c=3) #结果是:a = 1, b = (2,), c = 3。 func(1, 2, 3, 4, c=6) #结果是:a = 1, b = (2, 3, 4), c = 6。 # func(1, b=2, c=3) #报错
2、双星号(**)
- 双星号仅收集多余的关键字参数,并存放进一个字典中。没有多余的将是一个空字典。
- 定义函数时,双星号参数变量必须放在最后,即在无星号和单星号参数变量之后。
def func(a, b, **c): print('a = {}, b = {}, c = {}'.format(a, b, c)) func(1, b=2) #结果是:a = 1, b = 2, c = {} func(1, 2, c=3, d=4) #结果是:a = 1, b = 2, c = {'c': 3, 'd': 4}
3、单双星号结合使用
def func(a, b, c=6, *d, **e): print('a = {}, b = {}, c = {}, d = {}, e = {}'.format(a, b, c, d, e)) func(1, 2) #结果是:a = 1, b = 2, c = 6, d = (), e = {} func(1, 2, 3) #结果是:a = 1, b = 2, c = 3, d = (), e = {} func(1, 2, c=3, d=4) #结果是:a = 1, b = 2, c = 3, d = (), e = {'d': 4}。以但有星号后就与名称无关了,只是用于收集多余的位置参数或关键字参数 func(1, 2, 3, 4, d=4) #结果是:a = 1, b = 2, c = 3, d = (4,), e = {'d': 4}。要使*d接收到值,c只能使用位置参数的形式
2.4、分配参数(拆包)
- 分配参数:调用函数(而不是定义函数)时使用运算符*实现。
- 如果在定义和调用函数时都使用*或**,将只传递序列或字典。一般不建议这样使用。
- 只有在定义函数(允许可变数量的参数)或调用函数时(拆分字典或序列)使用,星号才能发挥作用。
1、单星号(*)
- 实参只能是序列。
def func(a, b, *c): print('a = {}, b = {}, c = {}'.format(a, b, c)) hh = [1, 2] func(*hh) #结果是:a = 1, b = 2, c = ()。传递一个列表,相当于func(1,2) hh = [1, 2, 3] func(*hh) #结果是:a = 1, b = 2, c = (3,)。相当于func(1,2,3) hh = (1,2) func(*hh) #结果是:a = 1, b = 2, c = ()。传递一个元组,相当于func(1,2) hh = 'abcd' func(*hh) #结果是:a = a, b = b, c = ('c', 'd')。传递一个字符串,相当于func('a','b','c','d')
2、双星号(**)
- 实参只能是字典。
def func(a, b, **c): print('a = {}, b = {}, c = {}'.format(a, b, c)) hh = {'a': 1, 'b': 2} func(**hh) #结果是:a = 1, b = 2, c = {}。相当于func(a=1,b=2) hh = {'a': 1, 'b': 2, 'c': 3} func(**hh) #结果是:a = 1, b = 2, c = {'c': 3}。相当于func(a=1,b=2,c=3) hh = {'a': 1, 'b': 2, 'c': 3, 'd': 4} func(**hh) #结果是:a = 1, b = 2, c = {'c': 3, 'd': 4}。
3、定义和调用都使用星号
def func(a, *b, **c): print('a = {}, b = {}, c = {}'.format(a, b, c)) hh = {'b': 2, 'c': 3, 'd': 4} gg = [1, 2, 3] func(*gg) #结果是:a = 1, b = (2, 3), c = {} # func(**hh) #报错 func(3, **hh) #结果是:a = 3, b = (), c = {'b': 2, 'c': 3, 'd': 4} func(*gg, **hh) #结果是:a = 1, b = (2, 3), c = {'b': 2, 'c': 3, 'd': 4} func(3, 4, *gg, **hh) #结果是:a = 3, b = (4, 1, 2, 3), c = {'b': 2, 'c': 3, 'd': 4} func(3, 4, gg, **hh) #结果是:a = 3, b = (4, [1, 2, 3]), c = {'b': 2, 'c': 3, 'd': 4} func(3, 4, *gg, hh) #结果是:a = 3, b = (4, 1, 2, 3, {'b': 2, 'c': 3, 'd': 4}), c = {}
3、函数的返回值
- 按是否有返回值,函数可分为两类:
- 有返回值的是真正意义上的函数,称为函数。
- 没有返回值的函数是不是函数的函数,称为过程式函数。
3.1、有返回值的函数
- 函数执行特定的操作并通过return返回一个值(可以是任意值,即返回什么由你决定)。
- return语句非常重要。
- 一是return语句用于从函数返回值,
- 二是return语句可以提前结束函数。
1、一个返回值的函数
def add(a, b): sum = a + b return sum #返回一个值 hh = add(3, 4) print(hh) #结果是:7
2、多个返回值的函数
- 要返回多个返回值时,它们将被放到一个元组中,并返回这个元组。
def add(a, b): sum = a + b return sum, a, b, 'jhahfdah' #返回多个值 hh = add(3, 4) print(hh) #结果是:(7, 3, 4, 'jhahfdah')。
3、return语句结束函数
def add(a, b): if a==0: return '第一个变量是零' sum = a + b return sum hh = add(0, 4) print(hh) #结果是:第一个变量是零
3.2、无返回值的函数:过程式函数
- 在Python中,什么都不返回的函数也是函数,即使它严格来说并非函数。
- 一是不包含return语句。
- 二是包含return语句,但没有在return后面指定值。
- 所有的函数都返回值。如果你没有告诉它们该返回什么,将返回None。
###示例1 def add(a, b): sum = a + b hh = add(0, 4) print(hh) #结果是:None ###示例2 def add(a, b): sum = a + b return hh = add(0, 4) print(hh) #结果是:None
4、变量作用域
4.1、作用域
- 每一个被声明的变量都存放在一个“看不见”的字典中,内置函数vars可以返回这个不可见的字典。
- 这种“看不见的字典”称为命名空间或作用域。
-
LEGB
- Python有很多名字空间,而 LEGB 则是名字空间的一种查找规则。
- LEGB 代表名字查找顺序: locals --> enclosing function --> globals --> __builtins__
- locals 是函数内的名字空间,包括局部变量和形参
- enclosing 外部嵌套函数的名字空间(闭包中常见)
- globals 全局变量,函数定义所在模块的名字空间
- builtins 内置模块的名字空间
>>> x = 1 >>> scope = vars() >>> scope['x'] 1 >>> x = 'maiheng' >>> scope['x'] 'maiheng' >>> vars() #返回这个不可见的字典 {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, 'x': 'maiheng', 'scope': {...}}
- 除全局作用域外,每个函数调用都将创建一个局部作用域。
def func1(): x = 3 y = 4 print('func1的作用域:', vars()) def func2(): x = 5 y = 6 print('func2的作用域:', vars()) x = 1 y = 2 print('全局作用域:', vars()) func1() func2() <<< 全局作用域: {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001A7030B0910>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'D:/test/python/day/test.py', '__cached__': None, 'func1': <function func1 at 0x000001A7032954C0>, 'func2': <function func2 at 0x000001A7032955E0>, 'x': 1, 'y': 2} func1的作用域: {'x': 3, 'y': 4} func2的作用域: {'x': 5, 'y': 6}
4.2、函数使用全局变量和局部变量
- 全局变量:不是函数中的变量,就是全局变量。
- 局部变量:在函数内使用的变量称为局部变量。函数的参数类似局部变量。作用范围仅在当前函数中
- 在函数中使用或修改不可变类型的全局变量(数、字符串、元组)时,必须先用global声明。
- 在函数中使用或修改可变类型的全局变量(列表、字典、集合和类式)时,不必用global声明。
- 局部变量和全局变量同名时,在函数中局部变量生效。
1、修改不可变类型的变量(数、字符串、元组)
def func(): global x, y, z #要修改全局变量,先有global声明 x += 4 y += 'ha' z += (4, 5, 6) print('func的作用域:', vars()) print('x = {}, y = {}, z={}'.format(x, y, z)) x = 1 y = 'heng' z = (1, 2, 3) print('全局作用域:', vars()) print('x = {}, y = {}, z={}'.format(x, y, z)) func() print('全局作用域:', vars()) print('x = {}, y = {}, z={}'.format(x, y, z)) <<< 全局作用域: {..., 'x': 1, 'y': 'heng', 'z': (1, 2, 3)} #全局作用域略写了 x = 1, y = heng, z=(1, 2, 3) func的作用域: {} x = 5, y = hengha, z=(1, 2, 3, 4, 5, 6) 全局作用域: {..., 'x': 5, 'y': 'hengha', 'z': (1, 2, 3, 4, 5, 6)} x = 5, y = hengha, z=(1, 2, 3, 4, 5, 6)
2、修改可变类型的变量(列表、字典、集合和类式)
def func(): a[2] = 10 b['y'] = 10 print('func的作用域:', vars()) print('a = {}, b = {}'.format(a, b)) a = [1, 2, 3] b = {'x': 1, 'y': 2, 'z': 3} print('全局作用域:', vars()) print('a = {}, b = {}'.format(a, b)) func() print('全局作用域:', vars()) print('a = {}, b = {}'.format(a, b)) <<< 全局作用域: {..., 'a': [1, 2, 3], 'b': {'x': 1, 'y': 2, 'z': 3}} a = [1, 2, 3], b = {'x': 1, 'y': 2, 'z': 3} func的作用域: {} a = [1, 2, 10], b = {'x': 1, 'y': 10, 'z': 3} 全局作用域: {..., 'a': [1, 2, 10], 'b': {'x': 1, 'y': 10, 'z': 3}} a = [1, 2, 10], b = {'x': 1, 'y': 10, 'z': 3}
3、局部变量遮住全局变量
def func(): x = 4 #局部变量和全局变量同名时,在函数中局部变量生效。函数中没有声明变量y,全局变量y生效 z = (4, 5, 6) print('func的作用域:', vars()) print('x = {}, y = {}, z={}'.format(x, y, z)) x = 1 y = 'heng' z = [1, 2, 3] print('全局作用域:', vars()) print('x = {}, y = {}, z={}'.format(x, y, z)) func() <<< 全局作用域: {..., 'x': 1, 'y': 'heng', 'z': [1, 2, 3]} x = 1, y = heng, z=(1, 2, 3) func的作用域: {'x': 4, 'z': (4, 5, 6)} x = 4, y = heng, z=(4, 5, 6)
4、解决遮住问题
- 必要时可以在函数中使用“globals()['全局变量名']”来访问全局变量。
- globals()内置函数,查看全局变量,以字典的形式输出(包含一些系统内置的变量)
- locals()内置函数,查看本地变量,以字典的形式输出。
def combine(hh2): hh1 = 'hh3 ' #局部变量hh1,形参hh2 print(globals()['hh1'] + hh1 + globals()['hh2'] + hh2) hh1 = 'hh1-' hh2 = 'hh2-' combine('hh4')
5、内部函数(套嵌函数)
- 内部函数:在函数中声明的函数。
- 内部函数可以访问外部函数的变量。
- 内部函数修改外部函数中可变类型的变量,不用nonlocal提前声明。
- 内部函数修改外部函数中不可变类型的变量,要用nonloca提前声明。
- 内部函数修改全局变量中可变类型的变量,不用global提前声明。
- 内部函数修改全局变量中不可变类型的变量,要用global提前声明。
def func(): n = 100 #声明一个不可变类型的变量 list1 = [9, 1, 7, 3, 8] #声明一个可变类型的变量 def in_func(): #声明内部函数 nonlocal n #修改外部不可变类型的变量要用nonlocal提前声明, global a #修改全局不可变类型的变量要用global提前声明 for index, i in enumerate(list1): list1[index] = i + n #修改外部可变 for index, i in enumerate(b): b[index] = i + n #修改全局可变 n += 11 a += 11 in_func() #调用内部函数 print('list1是:{}, n是:{}, b是:{}, a是:{}'.format(list1, n, b, a)) a = 10 #声明一个全局不可变类型的变量 b = [1, 7, 2, 9, 4] #声明一个全局可变类型的变量 func() #结果是:list1是:[109, 101, 107, 103, 108], n是:111, b是:[101, 107, 102, 109, 104], a是:21
6、闭包
- 闭包:是个嵌套函数(在外部函数中声明一个内部函数),内部函数中引用外部函数的变量,且外部函数的返回值是内部函数名。
- 闭包是特殊的内部函数
def func(a): def in_func(b): print('a是:{}, b是:{}'.format(a, b)) print(locals()) return in_func x = func(10) #结果是:{'in_func': <function func.<locals>.in_func at 0x00000243C5B755E0>, 'a': 10}。将内部函数的内存地址引用赋值给x print(x) #结果是:<function func.<locals>.in_func at 0x00000243C5B755E0> x(20) #结果是:a是:10, b是:20
- 闭包的作用之一,保存参数的状态。
def func(a, b): def in_func(c): sum = a + b + c print('{} + {} + {} = {}'.format(a, b, c, sum)) print(locals()) return in_func x1 = func(10, 20) #将外部函数的返回值--内部函数地址赋值给x1。 结果是:{'in_func': <function func.<locals>.in_func at 0x00000232BB5755E0>, 'a': 10, 'b': 20}。 x2 = func(100, 200) #每次引用内部函数都会开辟新的内存空间。 结果是:{'in_func': <function func.<locals>.in_func at 0x00000232BB575550>, 'a': 100, 'b': 200} x2(300) #结果是:100 + 200 + 300 = 600 x1(30) #结果是:10 + 20 + 30 = 60
示例:闭包之计数器
def generate_count(): container = [0] def add_one(): container[0] = container[0] + 1 print('当前是第{}访问'.format(container[0])) return add_one counter = generate_count() counter() #结果是:当前是第1访问 counter() #结果是:当前是第2访问 counter() #结果是:当前是第3访问
示例:闭包之同级调用、内部函数的返回值
def func(): a = 100 def in_func1(): b = 200 sum = a + b print('a + b =',sum) def in_func2(): in_func1() return '我是第二个内部函数' #内部函数的返回值 return in_func2 #外部函数的返回值 x = func() #将内部函数in_func2的内存引用赋值给x y = x() #将内部函数in_func2的返回值赋值给y。 结果是:a + b = 300 print(y) # 结果是:我是第二个内部函数
7、装饰器
- 装饰器:拥有闭包的特点,且只接受函数为参数。
- 装饰器是闭包,且将被装饰的函数当作实参。
- 在内部函数中调用以参数传进来的被装饰函数。
- 装饰器不改变原函数,也不改变原函数的调用方式,就可以给原函数添加新功能。
- 装饰器是特殊的闭包。
- 装饰器是python2.4引入的新语法,装饰器可用于包装任何可调用的对象,并且可用于函数和方法(类中的函数)。
7.1、装饰器的定义和使用
###定义装饰器 def 装饰器名(func): #第一层函数用于接收被装饰的函数 ... def 内部函数名(): #第二层函数用于接收被装饰函数的参数 ... func() return 内部函数名 ###使用装饰器 @装饰器名 #在程序执行到“@装饰器”和“def 被装饰函数名():”时,python解释器会自动在后台做: def 被装饰函数名(): #1、将“被装饰函数名”当参数传递给装饰器,并调用(执行)装饰器。 ... #2、将装饰器的返回值(内部函数引用的内存地址)赋值给“被装饰函数名” ###调用被装饰函数 被装饰函数名() #此时“被装饰函数名”引用的内存地址是装饰器内部函数的,而不是它自己的了
示例:
def decorate(func): #声明装饰器 def in_decorate(): print("八戒在吃自己的人参果...") print('八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...”') func() print(func) #打印被装饰函数自己引用的内存地址:<function bajie at 0x0000029317E55550> return in_decorate @decorate #使用装饰器 def bajie(): #声明被装饰函数 print('八戒伤心的哭了...') bajie() #调用被装饰函数 print(bajie) #打印被装饰后的被装饰函数引用的内存地址:<function decorate.<locals>.in_decorate at 0x0000029317E55670> <<< 八戒在吃自己的人参果... 八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...” 八戒伤心的哭了... <function bajie at 0x0000029317E55550> <function decorate.<locals>.in_decorate at 0x0000029317E55670>
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
def decorate(func): def in_decorate(): print("八戒在吃自己的人参果...") print('八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...”') func() return in_decorate @decorate def bajie(): print('八戒伤心的哭了...') bajie() <<< 八戒在吃自己的人参果... 八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...” 八戒伤心的哭了...
7.2、被装饰函数的参数
1、参数传递的两步
- 调用被装饰函数时,此时“被装饰函数名”引用的内存地址是装饰器内部函数的,即此时的"被装饰函数名"就是装饰器内部函数,因此参数会直接传递给装饰器内部函数。
- 装饰器内部函数得到此参数后,再传递给在其内部的原被装饰函数
def decorate(func): def in_decorate(x): #内部函数又将参数传递给原被装饰函数 print("八戒在吃自己的人参果...") print('八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...”') func(x) return in_decorate @decorate def bajie1(s): print('八戒伤心的哭{}天了...'.format(s)) @decorate def bajie2(lst): print('八戒伤心的哭了...') for i in lst: print('八戒喊来了%s,要他替自己做主。' % i) n = 9 bajie1(n) #传递一个整型作为参数。此时将参数传递给装饰器内部函数 list1 = ['师傅', '观音', '如来'] bajie2(list1) #传递一个列表作为参数 <<< 八戒在吃自己的人参果... 八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...” 八戒伤心的哭9天了... 八戒在吃自己的人参果... 八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...” 八戒伤心的哭了... 八戒喊来了师傅,要他替自己做主。 八戒喊来了观音,要他替自己做主。 八戒喊来了如来,要他替自己做主。
2、万能装饰器
- 只要是装饰器,一般都是这种万能装饰器。
def decorate(func): def in_decorate(*args, **kwargs): #装包,必须有*args和**kwargs print("八戒在吃自己的人参果...") print('八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...”') func(*args, **kwargs) #拆包,必须有*args和**kwargs return in_decorate @decorate def bajie1(): print('八戒伤心的哭了...') @decorate def bajie2(s): print('八戒伤心的哭{}天了...'.format(s)) @decorate def bajie3(lst, t=99): print('八戒伤心的哭%d了...' % t) for i in lst: print('八戒喊来了%s,要他替自己做主。' % i) bajie1() #调用时,使用无参数 n = 9 bajie2(n) #调用时,使用单个参数 list1 = ['师傅', '观音', '如来'] bajie3(list1, t=33) #调用时,使用关键字参数 <<< 八戒在吃自己的人参果... 八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...” 八戒伤心的哭了... 八戒在吃自己的人参果... 八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...” 八戒伤心的哭9天了... 八戒在吃自己的人参果... 八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...” 八戒伤心的哭33了... 八戒喊来了师傅,要他替自己做主。 八戒喊来了观音,要他替自己做主。 八戒喊来了如来,要他替自己做主。
7.3、多层装饰器
- 当一个被装饰函数有多个装饰器时,先使用离得最近的装饰器,然后依次使用较近的装饰器。
def zhuang1(func): #声明第一个装饰器 print('--------> start1') def in_1(): func() #2、这个func()就是zhuang() print('--------> 铺地板') print('--------> stop1') return in_1 def zhuang2(func): #声明第二个装饰器 print('--------> start2') def in_2(): func() #4、这个func()就是ni_1 print('--------> 买家具') print('--------> stop2') return in_2 @zhuang2 #离得较远的最后使用。 #3、将zhuang(此时的zhuang是in_1)作为参数传递给zhuang2,并将in_2赋值给zhuang @zhuang1 #先使用离得最近的装饰器。 #1、将zhuang作为参数传递给zhuang1,并将in_1赋值给zhuang def zhuang(): print('--------> 毛胚房') zhuang() #5、调用zhuang,此时的zhuang是in_2 <<< --------> start1 --------> stop1 --------> start2 --------> stop2 --------> 毛胚房 --------> 铺地板 --------> 买家具
7.4、装饰器的参数
- 装饰器如果要带参数,装饰器外面就要再嵌套一层函数,用于接收装饰器的参数,即一共有三层函数。
1、不带参数的装饰器
def banzhuan(func): #第一层函数用于接收被装饰的函数 def in_banzhuan(*args, **kwargs): #第一层函数用于接收被装饰函数的参数 func(*args, **kwargs) print('现在已经在铺设地板啦。。。') return in_banzhuan @banzhuan def maopei(time): print('{}买了这个毛胚房'.format(time)) maopei('2021-02-17') <<< 2021-02-17买了这个毛胚房 现在已经在铺设地板啦。。。
2、带参数的装饰器
def canshu(a): #第一层函数用于接收装饰器的参数 def banzhuan(func): #第二层函数用于接收被装饰的函数 def in_banzhuan(*args, **kwargs): #第三层函数用于接收被装饰函数的参数 func(*args, **kwargs) print('已经铺设%d地板啦。。。' % a) return in_banzhuan #在第二层函数中返回第三层的函数名 return banzhuan #在第一层函数中返回第二层的函数名 @canshu(100) #使用装饰器时,用的是第一层的函数名 def maopei(time): print('{}买了这个毛胚房'.format(time)) @canshu(10000) def road(): print('这是一条新修的小路') maopei('2021-02-17') road() <<< 2021-02-17买了这个毛胚房 已经铺设100地板啦。。。 这是一条新修的小路 已经铺设10000地板啦。。。
8、匿名函数
- 匿名函数简化函数的声明。
- 有些函数在代码中只用一次,且函数体比较简单,使用匿名函数可以减少代码量。
8.1、声明匿名函数
###使用关键字lambda声明匿名函数 函数名 = lambda 参数1,参数2...:返回值 #返回值是表达式
示例1:
add = lambda x, y: x + y #声明匿名函数 s = add(3, 5) #调用匿名函数 print(s) #结果是:8
示例2:三元运算
calc = lambda x, y: x * y if x > y else x / y print(calc(2, 5)) #结果是:0.4 print(calc(5, 2)) #结果是:10
8.2、匿名函数的使用场景
- 匿名函数主要和内置函数联合使用
1、map(function, sequence, ...)
- 内置函数map()有两个参数,一个是函数func,一个是序列,map将序列中的每个元素依次传入函数func中,并将结果返回到新的序列中。
示例1:
# 一般函数 list1 = [1, 2, 3, 4, 5, 6, 7, 8, 9] for index, val in enumerate(list1): list1[index] = val * val print(list1) #结果是:[1, 4, 9, 16, 25, 36, 49, 64, 81] # 匿名函数 list2 = [1, 2, 3, 4, 5, 6, 7, 8, 9] list2 = (map(lambda x: x * x, list2)) print(list(list2)) #结果是:[1, 4, 9, 16, 25, 36, 49, 64, 81]
示例2:
list1 = [1, 3, 2, 6, 3, 8, 9, 5, 0] result = map(lambda x: x if x % 2 == 0 else x + 1, list1) print(list(result)) #结果是:[2, 4, 2, 6, 4, 8, 10, 6, 0]
2、max(*args, key=None)
- 内置函数max(),返回最大值。
示例:
###离散值 max1 = max(3, 6, 1, 10, 44, 33) print(max1) #结果是:44 ###序列 list1 = [3, 6, 1, 10, 44, 33] max2 = max(list1) print(max2) #结果是:44 ###字典,比较复杂的数据需要指定以那个字段作比较 dict1 = [{'name': 'mai1', 'age': 55}, {'name': 'mai2', 'age': 33}, {'name': 'mai3', 'age': 77}, {'name': 'mai3', 'age': 11}, {'name': 'mai5', 'age': 22}] max3 = max(dict1,key=lambda x:x['age']) print(max3) #结果是:{'name': 'mai3', 'age': 77}
3、filter(function, sequence)
- 内置函数filter()有两个参数,一个是函数func,一个是序列,filter将序列中的每个元素依次传入函数func中,并根据返回结果决定是否该元素放进新的列表中。
###列表 list1 = [22, 55, 33, 1, 4, 22, 7, 99] list2 = filter(lambda x: x > 10, list1) print(list(list2)) #结果是:[22, 55, 33, 22, 99] ###字典 dict1 = [{'name': 'mai1', 'age': 55}, {'name': 'mai2', 'age': 33}, {'name': 'mai3', 'age': 77}, {'name': 'mai3', 'age': 11}, {'name': 'mai5', 'age': 22}] dict2 = filter(lambda x: x['age'] > 22, dict1) print(list(dict2)) #结果是:[{'name': 'mai1', 'age': 55}, {'name': 'mai2', 'age': 33}, {'name': 'mai3', 'age': 77}]
4、sorted(iterable[, cmp][, key][, reverse])
- 返回一个排序后的列表,其中的元素来自iterable(可迭代对象)。可选参数与列表的方法sort相同
###列表 list1 = [22, 55, 33, 1, 4, 22, 7, 99] list2 = sorted(list1) print(list(list2)) #结果是:[1, 4, 7, 22, 22, 33, 55, 99] ###字典 dict1 = [{'name': 'mai1', 'age': 55}, {'name': 'mai2', 'age': 33}, {'name': 'mai3', 'age': 77}, {'name': 'mai3', 'age': 11}, {'name': 'mai5', 'age': 22}] dict2 = sorted(dict1, key=lambda x: x['age']) print(dict2) #结果是:[{'name': 'mai3', 'age': 11}, {'name': 'mai5', 'age': 22}, {'name': 'mai2', 'age': 33}, {'name': 'mai1', 'age': 55}, {'name': 'mai3', 'age': 77}]
5、reduce函数
- reduce(func, seq[, initial])等价于func(func(func(seq[0], seq[1]), seq[2]), ...)
from functools import reduce tuple1 = (1, 4, 2, 5, 9, 3) tuple2 = reduce(lambda x, y: x + y, tuple1) print(tuple2) #结果是:24
9、递归函数
- 在函数内部,可以调用其他函数。如果一个函数在内部调用自己,这个函数就是递归函数。
- 基线条件(针对最小的问题):满足这种条件时函数将直接返回一个值。(必须有一个结束条件)
- 递归条件:包含一个或多个调用,这些调用旨在解决问题的一部分。
示例1:求n以内的正整数之和
def add(n): if n == 0: return 0 else: return n + add(n - 1) sum = add(100) print(sum) #结果是:5050
示例2、求n以内的正整数的阶乘
def factorial(n): if n == 1: return 1 else: return n * factorial(n - 1) ss =factorial(10) print(ss) #结果是:3628800
示例3:求x的n次幂
def power(x, n): if n == 0: return 1 else: return x * power(x, n - 1) ss = power(2, 10) print(ss) #结果是:1024