第四篇 函数
一.函数的定义
# 函数的定义 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)
# 固定写法 def deco(func): # 固定写法,这里的func将来接收的是add def wrapper(*args, **kargs): # 固定写法:这里的参数将来接收的时候 add函数的a 和 b 两个参数 result = func(args, kargs) # 新功能在内嵌函数里写 return result return wrapper # 固定写法;要把内嵌的函数返回 def add(a,b): pass
练习:输入某年某月某日,判断这一天是这一年的第几天?
import time def calDay(date): ''' 输入某个日期,计算是这一年的第几天 :param date: :return: ''' # 1. 先把输入的日期格式化 fenGefu = ['/','.','-','年','月'] try: for i in date: if i in fenGefu: date=date.replace(i,'-') elif i == '日': date=date.replace(i,"") # 2.利用time模块函数得到 forMatDate = time.strptime(date, '%Y-%m-%d') result = time.struct_time(forMatDate) # 3. 提取想要的结果返回 days = result.tm_yday return "{}是今年的地{}天".format(date, days) except Exception: print("您输入的日期格式不对,请检查后重新输入") date=input("请输入年月日:") print(calDay(date))
六.内置函数
1. 类型转换函数
bool , int , long ,float ,bytearray str, unicode, basestring,list tuple
set,dict, frozenset, complex
2.文件IO
input, print, open,file, format
3. 数学运算
abs,divmod, pow, sum, cmp, bin, oct, hex, chr, unichr, ord, max, min, round
# 1. 求模求余 divmod(99,1) # (14,1) #2. 求幂 pow(2,3) $ 8 # round()四舍五入, 有bug,慎用
4. 集合切片
len, range, iter, next, slice(切片), enumerate, sorted, reversed
data = ['a','b','c'] # enumerate 返回对象的下标
for i,v in enumerate(data):
print(i,v)
# 输出
0 a
1 b
2 c
5. 高阶函数
高阶函数:返回值是函数,或者函数的参数是函数
any(任意一个满足条件,返回True), all(所有满足条件,返回TRUE), map,reduce, filter, zip
map,reduce,filter是Python里很常用的三个高阶函数
map(func,iter):第一个参数是个函数,第二个参数要是一个可迭代对象
# map的第一个参数是个函数,第二个参数是个可迭代对象 # map的作用:对data数据里的每个元素,分别执行函数pow # map的返回是个map对象,所以,map的两种使用方法:1. 用list转化, 2.用for循环 data = [1,2,3,4,5,6,7,8,9] def pow(n): return n**n # map的第一个参数是个函数,第二个参数是个可迭代对象 # map的作用:对data数据里的每个元素,分别执行函数pow # map的返回是个map对象,所以,map的两种使用方法:1. 用list转化, 2.用for循环 # 使用list获取map的返回值 print(list(map(pow,data))) # 输出 [1, 4, 27, 256, 3125, 46656, 823543, 16777216, 387420489] # map函数用for循环取结果 for p in map(pow,data): print(p) # 输出 1 4 27 256 3125 46656 823543 16777216 387420489
# 还有更简单的,就是可以用lambda 匿名函数,替换 pow函数,就不用再定义上面的pow函数了 print(map(lambda n: n**2, data)) lambda 返回值:表达式
reduce(function,sequence): 第一个参数是个函数,
reduce():折叠函数,
# reduce函数:折叠函数 # 作用:类似于sum(), # 函数的运行方式:data里的1和2先相加得到3,然后再用3+ data里的3,得到6,然后用6再加data里的4,依次类推,直到data的最后一个数 from functools import reduce # reduce 在Python3里,要先导入才能使用 print(reduce(lambda x,y:x+y, data))
# 输出 45
filter(func, iter):过滤器
作用:filter函数作为过滤器,挑选满足条件的数据
# filter 函数 # 作用:filter函数作为过滤器,挑选满足条件的数据 # 从data里挑选出奇数 print(list(filter(lambda x:x % 2 !=0, data))) # 输出 [1, 3, 5, 7, 9]
# 从data里取出偶数 print(list(filter(lambda x:x % 2 == 0, data ))) # 输出 [2, 4, 6, 8]
6. 反射与内省
type, isinstance,issubclass,callable,staticmethod,classmethod,getattr, setattr, delattr,hasattr, super,dir,help,id,hash,object,__import__,compile,reload, repr,vars,locals,globals,eval,exec , execfile, property,memoryview