函数的作用
- 实现代码的重复利用
- 实现代码的模块性
- 确保代码的可扩展性
函数的定义
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号()。
- 任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数。
- 函数体的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
- return [表达式]结束函数,选择性地返回一个值给调用方。不带表达式的return和没有return相当于返回 None。
定义格式:
def functionname( parameters ):
"函数_文档字符串"
function_suite
return [expression]
注意
在 python 中,strings, tuples, 和 numbers 是不可修改的对象,而 list,dict 等则是可以修改的对象。
- 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5被丢弃,不是改变a的值,相当于新生成了a。
- 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。
将不可变对象a作为参数传入函数内,进行处理并不会影响函数外a的值;
将可变对象b作为参数传入函数内,进行处理会影响函数外b的值;
函数的调用
函数调用格式: 函数名()
实质是先通过函数名找到内存地址,在执行内存地址中的函数体代码
函数的参数
函数在def定义的时候,指明需要的参数,称这些参数为形参,不会占用内存空间。
函数在被引用的时候,传递给形参的参数,称之为实参,会占用内存空间
根据传递给形参时的不同方法,又分以下几类:
关键字参数:函数引用时,形参和实参的通过(形参=实参)建立传递关系;
位置参数:函数引用时,如果没有通过关键字参数建立传递关系,则他们通过位置顺序一一对应。注意
传递参数时,关键字参数不能在位置参数前面
默认参数:在函数定义的时候,可以为形参设的默认的值(形参=1),这个特别的形参称之为默认参数;默认参数的特点,调用函数的时候,默认参数可以不传递实参
动态参数:当无法确定形参数量的时候,可以在定义函数中使用参数组
*把函数引用时传递而来多个位置参数转换为一个元组
def test(*args)
print(args)
test(1,2,3,4)
args为一个元组=(1,2,3,4)
**把函数引用时传递而来的多个关键字参数,转换为字典
def stu_register(name,age,*args,**kwargs): # *kwargs会把多传入的关键字参数变成一个dict形式
print(name,age,args,kwargs)
stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong")
#输出
Jack 32 ('CN', 'Python') {'province': 'ShanDong', 'sex': 'Male'}
命名空间
内置命名空间: python解释器
用于存放python解释器启动就能使用的内置名字,在启动解释器时内置的名字就被加载进内存;无法调用全局、局部命名空间中的名字.
全局命名空间: 我们写的代码但不是函数中的代码
用于放置我们定义的所有变量名和函数名,在程序从上到下被执行的过程中依次加载进内容;在全局命名空间中可以调用内置名字空间的名字,但不能调用局部命名空间中的名字
局部命名空间: 函数中的代码
用于放置函数内部定义的名字,在函数被调用的时候才加载进内存;在局部命名空间中可以使用全局和内置命名空间中的名字;多个函数拥有多个独立的局部命名空间,相互独立。
作用域
全局作用域:
在全局可用,内置命名空间和全局命名空间属于全局作用域。
globals() 查看全局作用域中的变量
局部作用域:
只有在局部(函数、类内)可用,局部命名空间在相依的局部作用域中可用。
locals() 查看局部作用域中的变量
全局变量
在整个程序生效,列表,字典,和集合等可变对象可以在函数内被修改
局部变量
只在局部范围内生效,多用于函数内;函数内使用并修改全局变量(字符串和数值),需先global声明其为全局变量注意
:全局变量一定要在函数外声明,且不建议在函数内修改全局变量。
嵌套函数
在一个函数体内再调用一个函数,这就是嵌套函数;
内部函数可以引用外部函数的变量,但不能修改外部函数变量的值。
想要修改上一层函数的变量,使用nonlocal先声明该变量。
nonlocal
表⽰示在局部作⽤用域中, 调⽤用⽗父级命名空间中的变量.上一层没有则会再向上一层寻找,直到全局。
global
表⽰不再使⽤局部作用域中的内容了. ⽽改用全局作⽤用域中的变量.
闭包函数
在嵌套函数中,内部函数有调用外部函数的变量
,那么这个内部函数就是闭包函数,外部被调用的变量是自由变量。
def out():
c=[5]
def inner():
c[0]+=1
return c
return inner
foo=out() ##因为out函数中的return inner;故等号右边先执行,out()执行后foo指向了内部函数inner,且c=[5].
print(foo(),foo()) ##输出7,7
##print会等待()中的函数全部执行完毕才打印.
##第一个foo()返回名为c的内存单元,第二个仍返回名为c的内存单元。待打印时
##名为c的内存单元以及经过两次foo函数执行,其存放的值已变为7
print(foo()) #输出8
上面就是闭包的一种应用;通过外部函数中,return内部函数。此时可以在嵌套函数外调用内部函数,而且不会重复在内存中为外部函数变量a开辟空间。
递归函数
在函数内部调用函数自己,这个函数就称为递归函数,递归函数最多递归999次,其特性如下:
1、必须要有一个明确的结束条件
2、每次进入更深一层时,问题规模相比上次有所减少
3、递归效率不高,递归层次过多会导致栈溢出
def calc(n):
print(n)
if int(n/2) ==0:
return n
return calc(int(n/2))
calc(10)
输出:
10
5
2
1
匿名函数
lambda 参数列表:函数处理表达式
lambda x:x**2
(lambda x:print(x**2))(4)
前面的括号用于定义命名函数;第二个括号表达传递参数调用此匿名函数
高阶函数
将一个函数作为实参传递给另一个函数的形参。
def add(x,y,f):
return f(x) + f(y)
res = add(3,-6,abs)
print(res)
或者函数的输出是一个函数
def counter(base):
def inc(step=1):
nonlocal base
base += step
return base
return inc
f1=counter(5)()
print(f1)