第四篇 函数

it2026-01-09  9

一.函数的定义

# 函数的定义 def 函数名(形参): ''' 文档字符串 函数功能: 函数参数: 函数返回值 ''' function_body return [expression] # 函数的使用 函数名(实参) # 1. 函数的定义 def sayHello(name): print("你好,{},很高兴再次见到你".format(name)) return "{}来北京看我了".format(name) #函数的调用 print(sayHello("dali")) # 输出 你好,dali,很高兴再次见到你 dali来北京看我了

 

# 2. 函数可以没有参数 def Hello(): a= 3+4 return a print(Hello()) #输出 7

 

# 3. 定义一个变量,给变量的赋值是个函数名,就相当于把这个变量变成一个函数了 def sayHello2(name): print("你好,{},很高兴再次见到你".format(name)) return 1 message = sayHello2 print(message("xiaochengzi")) # 输出 你好,xiaochengzi,很高兴再次见到你 1

二.函数的参数

1. 必备参数 或者 位置参数

位置参数的特点:必须要给它传值,位置在最前面,定义了几个位置参数,调用函数的时候就必须传几个参数,否在会报错

# x,y 是位置参数,位置参数就是必须参数,函数调用时不能缺少 def add(x,y): return x+y print(add(2,3)) #5 # 错误示例 def add(x,y): return x+y print(add(2)) # TypeError: add() missing 1 required positional argument: 'y'

2. 默认参数

如果不想给某个参数传值,但是参数个数还不减少,那可以在函数声明时设置默认参数,就是给某个参数一个默认值,

如果不传值,函数调用时,默认就用的是设置的默认参数,如果传值了,函数调用时就用的是传的值

特点:默认参数的位置,一定要放到所有的位置参数的后面

# # j 定义时就给了个默认参数,如果j不传值,就默认取0, 默认参数一定要放在所有参数的最后面 def add1(i,j=0): return i+j print(add1(3)) # 3

3. 不定长参数

如果函数声明时,还不能确定到底会有多少个参数,可以定义不定长参数

特点:1) 不定长参数用*args表示, 2) *args的类型是元组 3)它的位置必须在默认参数后面

def add2(x,y=0,*args): print(args) return x + y print(add2(2)) # 输出 () # 此时x=2,y =0, *args没有传参,是个空元组 2 print(add2(4,5)) #输出 () # 此时x=4,y =5, *args没有传参,是个空元组 9 print(add2(1,3,5,7,9)) # 输出 (5, 7, 9) # 此时x=1,y =3, *args是个元组,其值是(5,7,9) 4 def add2(x,y=0,*args): print(args) return x + y + sum(args) # 使用参数,要去掉*号 print(add2(1,3,5,7,9)) #输出 (5, 7, 9) 25

4. 关键字参数

如果想传的参数是字典,就可以用关键字参数

特点:关键字参数 **kargs ,其类型是字典,必须最最后面,以 a = 1的形式传参

def add4(x,y,*args,**kwargs): print(kwargs) return x + y + sum(args) + sum(kwargs.values()) print(add4(1,3,3,4,5,a=1,b=5,c=5,d=-5)) # 输出 {'a': 1, 'b': 5, 'c': 5, 'd': -5} # 此时,x=1,y=3, args=(3,4,5),kwargs = {'a': 1, 'b': 5, 'c': 5, 'd': -5} 22

5. 形参与实参

 

 

三.函数的作用域

函数作用域的寻找顺序:Local -> enclosing->global -> build-in

1. L(Local)局部作用域

变量是在函数内定义的

a = 3 # 全局作用域 def scope(): a = 5 # 局部作用域 print(a) scope() # 输出 5

 

2. E(Enclosing)闭包函数外的函数中

见后面闭包的介绍

 

3.G (Global)全局作用域

变量是在函数外定义的,是整个文件的

a = 3 def scope(): print(a) scope() #输出 3

4. B(Built-in) 内建作用域

Python 自带的,预留的一些变量,函数名等

Python自带的不太适合举例说明

作用域的查找顺序是先局部,后全局,最后再内建,如果都没有该变量,就会报错

def scope(): print(a) scope() # NameError: name 'a' is not defined

5. 作用域有两个函数:Locals() 和 globals()

a = 3 def scope(): a = 5 print(globals()) # 输出 {'__name__': '__main__', '__doc__': '\n作用域生效机制\n局部 闭包函数外的函数中 全局 内建\n\n', '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x10511a470>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': '/Users/qiaoersun/Documents/千万别删/测试/Codes/testfanStudyPractice/lesson02/作用域.py', '__cached__': None, 'a': 3, 'scope': <function scope at 0x10529bd08>}

暂时还没弄明白

四.闭包(_closure_)

闭包的特点:

1. 闭包函数必须有内嵌函数

2. 内嵌函数需要引用嵌套函数的变量

3. 闭包函数必须返回内嵌函数

闭包的作用:

1. Python闭包就是装饰器(或叫修饰器)

2. 在不改原有函数任何内容的情况下,给原有函数增加功能

def greeting(name): ''' 1.在greeting函数中内嵌了一个greet函数 2.greeting函数的返回值是一个函数greet ''' def greet(): print(name) return greet # 函数的返回值是greet函数 # 定义一个func变量,调用greeting函数,因为greeting函数的返回值是greet,而greet也是个函数,所以就相当于func是个函数 # 此时只是返回了greet,greet函数并没有被调用,所以也不会有任何返回值 func = greeting('老刘') # 那么再调用func这个函数就等于是调用的下面的部分 ''' def greet(): print(name) ''' func() # 输出 老刘 # greeting()其实就是greet函数,那么也可以用下面的方式调用 greeting("小猫")() # 输出 小猫

对闭包函数的公式总结

def greeting(name): # 1. greeting函数里内嵌,嵌套了一个greet函数 --> 满足了:闭包函数必须有内嵌函数 a = 5 def greet(): # 2.在内嵌函数里引用了嵌套函数(greeting)的变量:a 和 name, 这个变量必须是内嵌函数外层已经定义的,不能是全局变量---> # 满足了:内嵌函数必须要引用嵌套函数的变量 print(name) print(a) # 3. greeting函数里返回了一个内嵌函数greet--->满足了:函数必须返回内嵌函数 return greet # 注意此处不能返回greet() # 4. 由上面3点的同时满足,才使得greeting成为一个闭包函数 # 5. 闭包函数的调用,在上面已经有了,此处略

在Python里闭包其实就是装饰器

五.装饰器

 装饰器的作用:就是为已经存在的对象添加额外的功能

 装饰器的应用场景:插入日志,性能测试,事务处理,缓存,权限校验等等

示例:计算一个函数执行用了多长时间

''' 闭包的作用: 1. 在Python闭包就是装饰器(或叫修饰器) 2. 在不改原有函数任何内容的情况下,给原有函数增加功能 利用闭包实现修饰器 ''' ''' 1. 计算原有函数wait()的执行时间,但是不能改wait()函数的任何代码 2. add()函数,把add()执行结果写入一个文件,不能改变add()函数的任何值 ''' import time import random ''' 解决办法:用闭包的方式解决,那么就要把原来已经存在的功能,即函数作为参数传递给闭包,此处形参用func代替 闭包一定是写在原还是的前面的 ''' # 2.用闭包的方式不改变原代码的情况下,新增计算时间的功能 def decorator(func): def wrapper(): startTime = time.time() result = func() endTime = time.time() print("测试结束,花费时间{}秒".format(endTime-startTime)) return result # 上面已经执行过了result,这里为什么还要再返回一下result?不返回会有什么影响? return wrapper ''' wait函数是已经存在的一段代码,假设有一万行,突然有个需求,要在wait上加一个功能,计算wait函数执行需要花多长时间 如果直接在wait函数上改,可能会引起其他bug,第二你也懒得看wait的代码,一个好的解决办法就是使用闭包,用装饰器来解决 这个问题 ''' # 1. 已有的功能 def wait(): w = random.randint(5,10) print(w) time.sleep(w) print("执行wait完毕,用了{}秒".format(w)) # 3. 调用闭包,获取执行结果 a = decorator(wait) # 相当于a 就是 wrapper函数里 a() # 再调用wrapper函数, 就能得到计算的结果 # 输出 9 执行wait完毕,用了9秒 测试结束,花费时间9.005208253860474秒

上面利用闭包写好了修饰器,但是闭包的使用不是像上面那样通过a = decorator(wait)()的方式使用的,而是通过在原有函数的上面加@闭包函数名的方式使用

import time import random # 2.用闭包的方式不改变原代码的情况下,新增计算时间的功能 def decorator(func): def wrapper(): startTime = time.time() result = func() endTime = time.time() print("测试结束,花费时间{}秒".format(endTime-startTime)) return result return wrapper # 3.通过@闭包函数名的方式,实现装饰器 @decorator # 1. 已有的功能 def wait(): w = random.randint(5,10) print(w) time.sleep(w) print("执行wait完毕,用了{}秒".format(w)) # 4. 直接调用原函数就可以实现功能 wait() # 输出 10 执行wait完毕,用了10秒 测试结束,花费时间10.002923727035522秒

 

# 示例2 ''' 已知:现有add函数 需求:add函数执行结果写到一个文件里去 ''' def writeAddtoFile(func): # 闭包的参数func,将来传的就是原有的功能函数add,这是永远不变的,套路,固定写法;外面的函数传函数名 def wrapper(a,b): # 内嵌函数的参数,接受的是原函数add的参数,这也是永远不变的,套路,固定写法;里面的函数传的才是参数 result = func(a,b) with open("add.txt",'a',encoding='utf-8') as f: f.write(str(result)+"\n") # 换行写入,要在写入的内容后面 加 +"\n" f.close() return wrapper @writeAddtoFile def add(x,y): return x+y add(5,8) add(3,5) add(1,1)

 

最新回复(0)