函数是结构化编程的核心。
函数可以提高代码的模块化和重复利用率。
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是实参。实参要和形参数量一致,且一一对应
'''
定义一个登录函数,参数是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>
def decorate(func):
def in_decorate():
print("八戒在吃自己的人参果...")
print('八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...”')
func()
return in_decorate
@decorate
def bajie():
print('八戒伤心的哭了...')
bajie()
<<<
八戒在吃自己的人参果...
八戒向猴哥讨要人参果,猴哥掂这八戒的大耳朵说“呆子,滚...”
八戒伤心的哭了...
View Code
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