什么时函数?
通俗的讲,函数就是写一段代码实现了某个小功能,然后把这些代码集中到一块,起一个名字,下次可以根据这个名字再次使用。
函数有什么作用?
- 方便代码的重用。
- 分解任务,简化程序逻辑。
- 是代码更加模块化。
函数有哪几类?
- 内建函数(Python自带函数)
- 第三方函数(第三方公司或者第三方个人开发出来的函数)
- 自定义函数
参数传输的方式:
多个参数
使用位置实参:直接用形参和实参一一对应
使用关键字参数:参数名称=参数(关键字参数)不需要严格按照顺序
使用容器作为实参:可以将一个列表或者字典作为一串参数传入函数。
不定长参数
1.在参数前面加一个*号代表不定长参数,函数中将会把这个变量作为元组来处理。(默认用*args)
之所以将这个变量当作元组处理而不作为列表处理,是因为在函数体中我们要尽可能直接改变参数。
2.在参数前面加俩个*号,以字典的方式来使用函数。这种方式定义的函数必须使用关键字参数进行传递。(默认使用**kwrgs)
这里有一个装包和拆包的概念,所谓装包就是将单独的个体整合成一个整体集合,例如使用*args和**kwrgs;而拆包则是将一个整体拆分为单独的个体。读取*args和**kwargs。
缺省参数:
缺省参数指的是参数在大多数情况下都是默认的情况,缺省参数在定义的时候需要使用关键字参数的方式传递,下面的形参sombody就是一个缺省参数。
def hit( sombody = "呼呼") :
print("我想打",sombody)ha
hit("nim")
函数参数的一些注意点:
首先要明确在函数中什么时值传递,什么是引用传递。
值传递:仅仅是将数据的副本传递过去,传递过去的值的地址跟原数据不一致,修改副本不会引起原来数据的变化。
引用传递:所谓引用传递就是地址传递,通过相同的地址操控同一份地址,在函数中改变形参会引起实参的变化。
一定要注意在Python中函数一般 都是引用传递。(地址传递)
如果要使用原数据的副本进行函数操作,可以使用切片的方法进行拷贝,传递过去的就是一份原数据的副本。
如果是不可变的数据类型,在函数中进行修改一定会改变它的地址;如果是可变数据类型,采用简单的添加删除不会修改地址,而直接重新赋值会出现新的地址。
函数的返回值:
当我们需要接收函数的处理结果时,就必须使用return来接收这个结果。一定注意:return只会执行一次,后面的代码不会再被执行。
return的结果可以时元组,列表,字典。
函数的表述信息:
当我们在写一个函数时一定要写一个函数的描述信息,写在开头用三个引号括起来。
在使用中可以使用help(函数名)来查看函数的功能。
函数描述信息必须包含的内容:
- 说明当前函数的功能。
- 说明函数参数的信息含义,数据类型,有没有默认值,有的话说明默认值。
- 说明函数的返回结果。
函数的高级功能:
偏函数:
什么时偏函数?当一个函数的默认参数大多数情况下时时不变的,但是有希望在指定的情况下改变其默认值,以此生成新的函数就是偏函数。我们可以通过functools模板的partial函数来改变函数的默认参数。
下面是一个使用偏函数的例子:
import functools
def test(a, b, c, d=2):
print(a + b + c + d)
test(1, 2, 3)
newTest = functools.partial(test, c=2)
newTest(1,1)
高阶函数:
当一个函数的参数接收的是另一个函数,那么这个函数就是一个高阶函数。
下面是一个高阶函数的例子,其中的sorted()就是一个高阶函数
l = [{"name":"s2","age":18} , {"name":"sz2","age":19} , {"name":"kc","age":20}]
def getKey(x):
return x["age"]
result = sorted(l , key = getKey)
print(result)
注意点:在将函数作为参数时使用的只是函数的名称,也就是说不用带上函数参数列表(括号)
返回函数:
返回参数指的是函数内部返回的数据是另外一个函数,把这样的操作称之为“返回参数”。
def getFun(flag) :
def sum( a, b , c) :
return a + b + c
def jianfa( a, b, c) :
return a - b - c
if flag == "+" :
return sum
elif flag == "-" :
return jianfa
function = getFun("+")
print(function(1, 2, 3))
匿名函数:
匿名函数称之为lambda函数,顾名思义就是指没有名字的函数,匿名函数只适合用于简单操作的函数。
使用的格式:lambda 参数1,参数2....:表达式(只能写一个表达式)表达式的结果就是匿名函数的返回值。总之先使用lambda作为统一函数名,再加上一个表达式,表达式的结果就是返回值。
下面是一个使用匿名函数的例子
result = (lambda x, y: x + y)(1, 2)
print(result)
l = [{"name": "s2", "age": 18}, {"name": "sz2", "age": 19}, {"name" :"kc","age": 20}]
result = sorted(l, key = lambda x: x["age"])
print(result)
闭包函数:
在函数嵌套的前提下,内层函数引用了外层函数变量(包括参数),而外层函数又把n内层函数当作返回值进行返回。
这个内层函数加上所引用的外层变量称之为闭包。
def test():
a = 10
def test2():
print(a + 7)
return test2
newFun = test()
newFun()
def line_config(content, length):
def line():
print("-"*(length//2) + content + "-"*(length//2))
return line
line1 = line_config("还哦",40)
line1()
line2 = line_config("还有我",80)
line2()
注意点:
在使用闭包函数时,如果要修改外层函数,必须在变量前面加上nonlocal声明,否则会被当作闭包内新定义的变量。
当函数被执行时里面的代码才会执行,在定义时是不会被执行的。
函数装饰器:
利用其它函数取装饰原本的函数。
装饰器适合做重复性,冗余度非常大的代码段落。一些基础业务逻辑代码的冗余度非常大,导致代码的复用性比较差,代码的维护性比较差。当我们要修改代码时,尽量在重用性非常高的地方进行修改,这时候装饰器的优势非常大。
函数的使用要遵循单一职责,函数内容单一优先实现函数名的功能。
下面是一些使用函数装饰器的案例:
def checklogin(func) :
"""
这是一个要用来做装饰器的函数,这个函数可以让其它函数增加登陆验证的操作
"""
def inner() :
"""
这是一个闭包函数,用来接收其它函数功能,使他们的功能和登陆验证结合起来
"""
print("正在登陆验证....")
func()
return inner
@checklogin # 装饰器的写法,相当于对下面的函数进行更新,是下面的发说说函数增加一个登陆验证操作
def fss() :
print("发说说!")
# fss = checklogin(fss)
@checklogin # 装饰器的写法,相当于对下面的函数进行更新,是下面的发图片函数增加一个登陆验证操作
def ftp():
print("发图片!")
# ftp = checklogin(ftp)
fss()
ftp()
案例2:装饰器叠加:从上到下进行叠加;从下到上进行叠加。
def print_line(funce2) :
"""
这是一个用来做装饰器的函数,给其它函数增加打印------的功能
"""
def inner() :
print("-" * 30)
funce2()
return inner
def print_star(funce2) :
"""
这是一个用来做装饰器的函数,给其它函数增加打印*****的功能
"""
def inner() :
print("*" * 30)
funce2()
return inner
@print_star #使用上面的俩个装饰器连续修饰,从下往上看。
@print_line
def print_name() :
print("I am Linjunhan !")
案例3:对有参数的函数进行装饰
def zsq(func) :
"""
这是一个用来做修饰器函数,用来打印-------信息
"""
def inner(*args ,**kwargs) :
print("-" * 30)
func(*args ,**kwargs)
return inner
@zsq
def pnum(num) :
print(num)
@zsq
def pnum2(num1,num2) :
print(num1,num2)
案例4:对有返回值的函数进行修饰。
def zsq(func):
def inner(*args, **kwargs):
print("-" * 30)
res = func(*args, **kwargs)
return res
return inner
@zsq # pnum = zsq(pnum)
def pnum(num1, num2, num3):
return num1 + num2 + num3
print(pnum(1, 2, 3))
案例5:带有装饰的修饰器 ,通过@修饰器(参数)的方式调用这个函数,并传递参数;并把返回值再次当作修饰器来使用。
def zsqs(char):
def zsq(func):
def inner():
func()
print(char * 30)
return inner
return zsq
@zsqs("*") # 利用函数调用zsq修饰器。
def f1():
print("666666")
f1()
生成器(特殊的迭代器):
生成器具有迭代器的特征:
惰性计算数据,节省内存,一个一个拿出来用。
能够记录数据,并通过next()函数,访问下一个函数。
具备可迭代性。
创建方式:把列表推导式[]改为()
生成器函数:
利用表达式创建:
l = (i for i in range(1, 100000) if i % 2 == 0)
print(next(l))
print(next(l))
print(next(l))
创建方式2:
def test():
print("xxx")
yield 1
print("a")
yield 2
print("b")
yield 3
print("c")
yield 4
print("d")
yield 5
print("e")
g = test()
print(g)
超出范围,迭代停止。
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
return 'done'
f = fib(10)
print('fib(10):', f)
for x in f:
print(x)
# 超出范围,迭代停止
def test2() :
print("xxxx")
res1 = yield 1
print(res1)
res2 = yield 2
print(res2)
res3 = yield 3
print(res3)
g = test2()
# print(g.__next__()) ##采用.__next__()的方法来访问迭代器
#利用生成器的.send方法,这个方法有一个参数,时用来指定上一次被挂起的yield的返回值,如果第一次调用,参数必须为空。
# print(g.send())
print(g.__next__())
print(g.send("6666"))
g.close() # 生成器的关闭方法
递归函数(在函数内部再次调用函数)
def jiecheng(n):
"""
这个递归函数用计算参数n的阶乘
:param n:
:return:
"""
if n == 1:
return 1
return n * (n - 1)
print(jiecheng(3))