定义: 函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。
函数的好处
1、简化代码
2、提高代码的复用性
3、代码可扩展
定义函数使用def关键字,后面是函数名,函数名不能重复
def fun():#定义一个函数,后面是函数名
print("Hello World")#函数体
函数在调用的时候,可以传入参数,有形参和实参,简单点说,形参就是函数定义接收的参数,而实参就是调用时传入的参数。
形参:形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。
实参:实参可以是常量、变量、表达式、函数。
def calc(x,y):#定义一个函数,参数有x和y,x和y就是形参
print(x*y)#输出x乘以y的值
calc(5,2)#调用上面定义的函数,5和2就是实参
函数的形参类型
位置参数,字面意思也就是按照参数的位置来进行传参,有几个位置参数在调用的时候就要传几个,否则就会报错了。
默认参数就是在定义形参的时候,给函数默认赋一个值
可变参数
可变参数用*来接收,不是必传的;
它把传入的元素全部都放到了一个元祖里;
不显示参数个数,后面想传多少个参数就传多少个
如果位置参数、默认值参数、可变参数一起使用的的话,可变参数必须在位置参数和默认值参数后面。
关键字参数
关键字参数使用**来接收
返回的是字典
不限制参数个数,非必传
如果位置参数、默认值参数、可变参数、关键字参数一起使用的的话,关键字参数必须在最后面
例子:
def my(name,country='china',*args,**kwargs):
print(name)
print(country)
print(args)
print(kwargs)
my(‘TT‘,’2’,’3’,’4’,’5’,a='6',b='7')
函数重载
python中是不支持函数重载的,但在python3中提供了这么一个装饰器functools.singledispatch,它叫做单分派泛函数,可以通过它来完成python中函数的重载,让同一个函数支持不同的函数类型。
from functools import singledispatch
@singledispatch
def show(obj):
print (obj, type(obj), "obj")
@show.register(str)
def _(text):
print (text, type(text), "str")
@show.register(int)
def _(n):
print (n, type(n), "int")
show(1)
show("xx")
show([1])
匿名函数:
函数名 = lambda 参数 :返回值
#参数可以有多个,用逗号隔开
#匿名函数不管逻辑多复杂,只能写一行,且逻辑执行结束后的内容就是返回值
#返回值和正常的函数一样可以是任意数据类型
函数在内部调用自身本身,这个函数就是递归函数。
理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。
使用递归函数需要注意防止栈溢出。
解决递归调用栈溢出的方法是通过尾递归优化,事实上尾递归和循环的效果是一样的,所以,把循环看成是一种特殊的尾递归函数也是可以的。
尾递归,把当前的运算结果(或路径)放在参数里传给下层函数,并且return语句不能包含表达式。这样,编译器或者解释器就可以把尾递归做优化,使递归本身无论调用多少次,都只占用一个栈帧,不会出现栈溢出的情况。
遗憾的是,大多数编程语言没有针对尾递归做优化,Python解释器也没有做优化,所以,即使把上面的fact(n)函数改成尾递归方式,也会导致栈溢出。
def func(n,mul=0):
if n==0:
return mul
else:
return func(n-1,n+mul)
print(func(997,0))
默认,mac上n超过997时栈溢出
import sys
sys.setrecursionlimit(9000000) #这里设置大一些
但是即使这样,超过20000还是会栈溢出
可变/不可变类型
数据类型 |
可变/不可变 |
整型 |
不可变 |
字符串 |
不可变 |
元组 |
不可变 |
列表 |
可变 |
集合 |
可变 |
字典 |
可变 |