函数的主要功能是可以打包代码,最大程度的实现代码的重用,减少冗余代码,可以将不同功能的代码进行封装,从而降低结构的复杂度,提高代码的可读性。
创建和调用函数
使用def语句来定义函数。
def myFunc():print("这是我编写的第一个函数")
myFunc()
注意:在编写程序时可以在函数体内使用pass语句,这是一个空语句,用于占位,日后再完善。
函数的参数
形式参数是指在定义函数时写的参数名,实际参数是指在调用函数时传入的参数值。可以通过设定参数来实现对函数的个性化定制。
def myFunc(name,time):for i in range(time):print(f"你好!{name}")
myFunc("Kiven",3)
位置参数
实参是按照形参定义的顺序进行传递的。将python中参数的名字和位置确定下来的参数称之为位置参数。作为参数的调用者,只需要按照顺序传递正确的参数即可。
def myFunc(a,b,c):return "".join((c,b,a))
print(myFunc("我","爱","你"))
关键字参数
使用关键字参数只需要知道参数的名字,可以不管参数的顺序。
def myFunc(c,b,a):return "".join((c,b,a))
print(myFunc(a = "我",b = "爱",c = "你"))
注意:位置参数和关键字参数可以混用,但位置参数必须在关键字参数之前。
默认参数
python允许函数的参数在定义的时候就指定默认值,在函数调用时,如果没有传入实参,那么就将采用默认的参数值来进行代替。
def myFunc(a,b,c="你"):return "".join((a,b,c))
print(myFunc("我","爱"))
print(myFunc("我","爱","python"))
注意:若使用默认参数,应将其定义在参数列表的最后。
/(斜杠)左侧的参数必须传递位置参数,而不能是关键字参数。
help(abs)
help(sum)
*(星号)标识其左侧既可以是位置参数,也可以是关键字参数,但是右侧只能是关键字参数。
def abc(a,*,b,c):print(a,b,c)
print(abc(1,b=2,c=3))
print(abc(1,2,3))
收集参数
用户可以根据自己的需求,随意的传入一个或者多个参数,拥有这种特性的形参被称之为收集参数。使用*(星号)来表示此参数是收集参数。
通过*(星号)就是实现了打包的操作,参数列表是以元组的形式输出出来的。
def myfun(*args):print("此函数拥有{}个参数".format(len(args)))print("第2个参数是{}".format(args[1]))print(args)
myfun(1,2,3,4,5)
注意:如果在收集参数后面还需要指定其他参数,那么在调用函数的时候,就应该使用关键字来指定后面的参数。否则python就会把实参纳入到收集参数中。
def myfun(*args,a,b):print(args,a,b)
myfun(1,2,3,4,5)
除了可以将多个参数打包成元组,还可以使用两个连续的*(星号)将多个参数打包成字典。
def myfun(**kwargs):print(kwargs)
myfun(a = 1,b = 2,c = 3)
解包参数
使用*(星号)将包含多个元素的变量进行解包,满足函数参数个数的要求。
args = (1,2,3,4)
def myfun(a,b,c,d):print(a,b,c,d)
myfun(*args)
连续的两个星号代表解包关键字参数。
kwargs = {'a':1,'b':2,'c':3,'d':4}
def myfun(a,b,c,d):print(a,b,c,d)
myfun(**kwargs)
函数的返回值
使用return语句,将自定义的函数实现返回值。
函数可以返回多个值。python使用元组对要返回的值进行打包。
def div(x,y):if y == 0:print("除数不能为0")else:return x/y
div(6,0)
print(div(8,2))
注意:函数在执行到return后会立即返回并结束,不会理会return语句后是否还有语句。如果没有使用return语句显式的返回内容,那么函数也会在执行完函数体中的所有语句后,返回一个None。
作用域
所谓的作用域就是指一个变量可以被访问的范围。通常一个变量的作用域,总是有它在代码中被赋值的位置来决定的。
局部作用域
如果一个变量定义的位置是在函数内,那么它的作用域就仅限于该函数,称之为局部变量。
全局作用域
如果是在任何函数的外部去定义一个变量,那么它的作用域就是全局的,称之为全局变量。
在函数中,局部变量会覆盖同名全局变量,但在函数外全局变量的值并不会因为同名的局部变量而发生改变。
global语句
可以使用global语句在函数内修改全局变量的值。
x = 1314
def myfun():global xx = 520
myfun()
print(x)
嵌套函数
在一个函数的内部对另外一个或者多个函数进行定义并使用。
def funA():x = 520def funB():x = 1314print("funB x=",x)funB()print("funA x=",x)
funA()
所嵌套的内部函数是无法被调用的,只可以在外层函数中进行调用。
def funA():x = 520def funB:X = 1314print("funB x=",x)print("funA x=",x)
funB()
注意:内部函数可以访问到外部函数的变量,但是无法修改它。
nonlocal语句
如果非要在内部函数去修改外部函数的变量,可以使用nonlocal语句。
def funA():x = 520def funB():nonlocal xx = 1314print("funB x=",x)funB()print("funA x=",x)
funA()
LEGB规则(local,enclosed,global,build-in)
当作用域相互覆盖发生冲突时,根据LEGB规则进行处理。
闭包
闭包也可以被称之为工厂函数,相当于一条已经组装好的生产线,我们只需要调整生产线参数就可以生产不同的东西,而不需要重新组装生产线。是指一个函数可以“记住”并访问其定义时的作用域中的变量,即使在函数外部调用该函数时,依然能够访问到这些变量。
def power(exp):def exp_of(base):return base ** expreturn exp_of
square = power(2)
cube = power(3)
print(square(5))
print(cube(5))
利用内层函数能够记住外层函数作用域的特性,并且使用nonlocal语句进行操作,让其可以修改到外层函数作用域的里面的这个变量,就可以实现一个带记忆功能的一个函数。
def outer():x = 0y = 0def inner(x1,y1):nonlocal x,yx+=x1y+=y1print(f"x = {x},y = {y}")return inner
move = outer()
move(1,2)
如果将函数作为返回值来返回时,只需要写入函数的名字即可。使用函数名()()的形式可以直接调用作为返回值的函数。
def funA():x = 520def funB():print(x)return funB
funA()()
def funA():x = 520def funB():print(x)return funB
y = funA()
y()
注意:对于嵌套函数来说,外层函数的作用域是会通过某种形式给保存下来的,尽管这个函数已经被调用完了,但是外层作用域里面的变量是会被保存下来的,并不会像局部作用域那样,调用完就消失了。
装饰器
函数的函数名可以通过在函数名后添加()(小括号)来表示调用函数。
def myfun():print("正在调用myfun")
def report(fun):print("开始调用函数")fun()print("调用结束")
report(myfun)
时间管理函数
import time
def time_master(fun):print("开始运行程序!")start = time.time()fun()end = time.time()print("程序结束运行!")print(f"程序运行一共耗费了{(end-start):.2f}秒")def myfun():time.sleep(2)print("Hello python")time_master(myfun)
装饰器就是闭包+函数当参数
使用装饰器可以不用修改代码,只需要在函数的上方加上一个@装饰器名(语法糖),然后正常调用函数即可实现想要实现的功能。
import time
def time_master(fun):def call_fun():print("开始运行程序!")start = time.time()fun()end = time.time()print("程序结束运行!")print(f"程序运行一共耗费了{(end-start):.2f}秒")return call_fun
@time_master
def myfun():time.sleep(2)print("Hello python")myfun()
相当于在后面调用myfun函数时,并不是直接去调用myfun函数,而是把myfun这个函数作为一个参数,添加到上面的装饰器中,然后去调用这个装饰器。
多个装饰器可以同时作用在同一个函数,并且修饰器的作用由近到远。
def add(fun):def inner():x = fun()return x+1return innerdef cube(fun):def inner():x = fun()return x*x*xreturn innerdef square(fun):def inner():x = fun()return x*xreturn inner@add
@cube
@square
def test():return 2
print(test())
给装饰器传递参数
添加一次调用,然后通过这次调用将参数传递进去。
import time
def logger(msg):def time_master(fun):def call_fun():print("开始运行程序!")start = time.time()fun()end = time.time()print("程序结束运行!")print(f"{msg}程序运行一共耗费了{(end-start):.2f}秒")return call_funreturn time_master
@logger(msg = 'A') #等价于funA = logger(msg='A')(funA)
def myfunA():time.sleep(2)print("正在调用函数A")
@logger(msg = 'B') #等价于funB = logger(msg='B')(funB)
def myfunB():time.sleep(1)print("正在调用函数B")myfunA()
myfunB()
lambda表达式
lambda arg1,arg2,arg3......argN:expression
lambda是一个匿名函数,24冒号左边是传入函数的参数,冒号右边是函数实现表达式以及返回值。
def square1(x):return x*x
print(square1(3))square2 = lambda y : y*y
print(square2(3))
注意:lambda是一个表达式,他可以用于常规函数不可能存在的地方(lambda的优势)。
比如说列表中。
y = [lambda x:x*x,2,3]
print(y[0](y[1]))
生成器
定义生成器就是使用yield表达式来代替函数中的return语句。函数每次执行到yield语句时,就生成一个数据,暂停并保留状态,下一次调用则从下一个语句开始继续执行。
生成器不像列表、元组等可迭代对象。生成器是一台制作机器,其作用是每次调用提供一个数据,并且会记住当时的状态。列表、元组等是一个容器,它们存放的是早已经准备好的所有数据。
生成器是一种特殊的迭代器,首先它不走回头路,第二支持next函数。生成器无法使用下标这种随机访问的方式的。
def counter():i = 0while i <= 5:yield ii+=1
print(type(counter()))
for i in counter():print(i)
c = counter()
next(c)
next(c)
next(c)
next(c)
next(c)
next(c)
next(c)
生成器表达式 、
生成器表达式和列表推导式的不同是,列表推导式会一下子将所有的数据生产出来,而生成器表达式则一次只产生一个数据。
t = (i ** 2 for i in range(10))
print(type(t))
for i in t:print(i)
递归
递归函数其实就是函数调用自身。
让递归正常工作需要在递归函数的开始位置加入正确的结束条件判断。
def factRecur(n):if n == 1:return 1else:return n * factRecur(n-1)
print(factRecur(5))
递归的效率比迭代高很多。
函数文档
使用help()函数就可以快速查看到函数的使用文档。
创建函数文档
在函数的开头使用"""来编写函数文档。函数文档一定在函数的最顶部
def exchange(dollar,rate=7.19):"""功能:汇率转换 美元->人民币:param dollar: 美元数量:param rate: 汇率 默认值为7.19(2025-5-29):return: 人民币数据"""return dollar*rate
print(exchange(100))
print(help(exchange))
类型注释
其中s被指定为字符串类型,n被指定为int类型,->str表示返回值被指定为字符串类型。这里的类型只是函数创作者的期望,如果函数的参数没有传入期望的数据类型,python也不会报错。
def times(s:str,n:int)->str:return s*n
print(times("hello",5))
print(times(5,5))
如果需要默认参数,我们可以在数据类型之后添加赋值号(=)和默认值。
内省
内省是指在程序运行的时候能够进行自我检测的一种机制。
使用__name__查看名字
使用__annotations__查看类型注释
使用__doc__查看文档
def times(s:str,n:int)->str:return s*n
def exchange(dollar,rate=7.19):"""功能:汇率转换 美元->人民币:param dollar: 美元数量:param rate: 汇率 默认值为7.19(2025-5-29):return: 人民币数据"""return dollar*rate
print(times.__name__)
print(times.__annotations__)
print(exchange.__doc__)
高阶函数
函数可以当作参数传来传去,当函数接收另外一个函数,使函数当作参数的时候,将这种函数称之为高阶函数。
functools包含了多种高阶函数和装饰器。
reduce(函数,可迭代对象)函数
第一个参数是指定一个函数,第二个参数是一个可迭代对象。其作用就是将可迭代对象中的元素依次传递到第一个参数指定的函数中,最终返回累计的结果。
import functools
def add(x,y):return x+y
print(functools.reduce(add,[1,2,3,4,5]))
partial()函数(偏函数)
是指对指定的函数进行二次包装。通常是将现有的函数的部分参数预先绑定。其作用是将一个函数的多个参数给拆分,多次进行传递。
import functools
square = functools.partial(pow,exp = 2)
print(square(2))
@wraps装饰器
用于装饰装饰器,显示调用的函数,而不是实际调用的函数。
import time
import functools
def time_master(fun):@functools.wraps(fun)def call_fun():print("开始运行程序!")start = time.time()fun()end = time.time()print("程序结束运行!")print(f"程序运行一共耗费了{(end-start):.2f}秒")return call_fun
@time_master
def myfun():time.sleep(2)print("Hello python")myfun()
print(myfun.__name__)