1.创建函数
定义函数使用def语句
#计算斐波那契数列
def fibs(n):
res=[0,1]
for i in range(n-2):
res.append(res[-1]+res[-2])
return res
while True:
m=int(input())
print(fibs(m))
#Input:7
#Output:[0, 1, 1, 2, 3, 5, 8]
2.函数的文档注释
为函数添加文档注释,需要在def语句那一行的下一行用一对单引号或双引号将注释括起来。
为函数写了文档注释后,可以使用“__ doc __”函数或“ help ”函数获取函数的文档注释。
def fibs(n):
"计算斐波那契数列"
res=[0,1]
for i in range(n-2):
res.append(res[-1]+res[-2])
return res
help(fibs)
#Output:
fibs(n)
计算斐波那契数列
print(fibs.__doc__)
#Output:计算斐波那契数列
3.函数参数的传递
如果传递的变量类型是数值、字符串、布尔等类型,则是值传递。
值传递即在传递时将自身复制一份,函数内部接收到的参数实际上是传递给函数的变量的副本,故在函数内部对参数变量进行修改并不会影响到原始变量。
如果传递的变量类型是序列、对象等复合类型,则是引用传递。
引用传递即在传递时复制的不是变量中的数据,而是变量的引用。因为这些复合类型在内存是用一块连续或不连续的内存空间保存,要想找到这些复合类型的数据,必须得到这些内存空间的首地址,而这个首地址就是复合类型数据的引用。故在函数内部对复合类型参数变量进行修改也会影响到原始变量。
4.关键字参数
def qqq(name,age):
return "名字:{},年龄:{}".format(name,age)
#使用位置参数,传递过去的值是位置对应的
print(qqq("Bill",12)) #Output: 名字:Bill,年龄:12
#使用关键字参数,位置可以随意
print(qqq(age=10,name="Mike")) #Output: 名字:Mike,年龄:10
#上述两种混用,关键字参数必须放在位置参数后面,否则会抛出异常
print(qqq("John",age="20")) #Output: 名字:John,年龄:20
5.可变参数
像print函数这样可以传递任意多个参数的形式称为可变参数。定义函数的可变参数需要在形参前面加一个星号(*)
可变参数在函数内部是以元组的形式体现的,故在函数内部可以像元组一样使用可变参数的具体参数值。
def output(*p):
print(p)
output("hello",2,True,100) #Output:('hello', 2, True, 100)
既有普通参数又有可变参数时,可变参数要放在最后。若想放在中间或最前面,则其后面的普通参数在进行参数值传递时要使用关键字参数形式,或者为后面的普通参数指定默认值。
def output(val,*p):
print(val,end=" ")
for i in p:
print("<"+str(i)+">",end=" ")
output("hello",2,True,100) #Output:<hello> <2> <True> <100>
6.将序列作为函数的参数值
除了可以直接将序列作为单个的参数传入函数外,我们还可以将序列的每个元素单独作为函数的参数值,相当于把序列拆开进行传值。
将序列(列表、元组、字典、字符串等)中的元素拆开成单个参数传递给函数,需要在实参前面加星号(*)。
def Output1(s1,s2,s3): #传递进来的序列元素有几个则形参就得有几个
print(s1,s2,s3)
def Output2(*s): #或者用可变参数
print(s,end=" ")
for i in s:
print(i,end="~")
L=["hello","world",2020]
Output1(*L) #Output:hello world 2020
Output2(*L) #Output:('hello', 'world', 2020) hello~world~2020~
Output2(L) #Output:(['hello', 'world', 2020],) ['hello', 'world', 2020]~
#Output1(*"LOVE") #出现异常,函数形参只有3个
Output2(*"LOVE") #Output:('L', 'O', 'V', 'E') L~O~V~E~
Output2("LOVE") #Output:('LOVE',) LOVE~
将字典中的元素作为单个参数传入函数时,形参实参都要使用两个星号。
def Output1(**s):
print(s,end=" ")
for i in s:
print(i,end="~")
def Output2(s):
print(s,end=" ")
for i in s:
print(i,end="~")
L={'a':1,'b':2,'c':3}
Output1(**L) #Output:{'a': 1, 'b': 2, 'c': 3} a~b~c~
Output2(L) #Output:{'a': 1, 'b': 2, 'c': 3} a~b~c~
7.作用域
作用域分为全局作用域和在函数本身的局部作用域。
在python语言中,不管在作用域的哪个位置为变量赋值,都会认为这个变量属于当前作用域,而且会隐藏上层作用域同名的变量。
如果在当前函数中没有定义局部变量x,那么当前函数会从上一个作用域开始查找,直到找到变量x或到了全局作用域为止。
x=123
def fun():
print(x) #先访问全局变量x,再定义局部变量x,这是不行的,会抛出异常
x=10
fun()
8.函数嵌套和返回函数以及闭包
python语言中,函数支持嵌套,即可以在一个函数中定义另一个函数。并且可以直接返回函数本身(相当于C中返回函数的指针)
x=30
def fun1():
x=10
def fun2(): #嵌套函数
print(x)
return fun2 #返回fun2函数本身
fun1()() #调用了fun1的嵌套函数fun2
#Output:10
关于返回函数:
def fun(y):
def cal(x):
return 2*x+y
return cal
qwe=fun(4)
print(qwe(5)) #Output:14
print(fun(4)(3)) #Output:10
闭包:如果在一个内部函数里,对在外部作用域(但不是在全局作用域)的变量进行引用,那么内部函数就被认为是闭包(closure).
(上面两份代码均是闭包的示例,具体内容及作用待以后学习)
9.global关键字和nonlocal关键字
函数内部不支持对不在当前作用域的变量进行修改,示例如下。
#函数内部修改全局作用域变量
def qqq1():
x+=1 #x是全局变量,能直接访问和直接使用,但不能进行修改
print(x)
def qqq2():
x=20 #在函数局部作用域重新定义了x,会覆盖全局x,所以能进行修改了
x+=1
print(x)
x=100
qqq1() #UnboundLocalError: local variable 'x' referenced before assignment
qqq2() #Output:21
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#函数内部修改上一个作用域变量
def www():
y=10
def eee():
y+=1 #y是上一个作用域的变量,所以也不能修改,只能直接访问和使用
print(y)
return eee
www()() #UnboundLocalError: local variable 'y' referenced before assignment
若想对不在当前作用域的变量进行修改,则需要使用global关键字或nonlocal关键字,示例如下。
#在函数中需要修改全局变量,则需要使用global关键字
def qqq1():
global x
x+=1
print(x)
x=100
qqq1() #Output:101
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#在函数中需要修改上一级作用域变量,则需要使用nonlocal关键字
def www():
y=10
def eee():
nonlocal y
y+=1
print(y)
return eee
www()() #Output:11