定义:
函数是组织好的,可重复使用的,用来实现单一,或相关联功能的代码段。
目的:
函数能提高应用的模块性,和代码的重复利用率。
分类:
内建函数、自定义函数。
你已经知道Python提供了许多内建函数,比如print()。
但你也可以自己创建函数,这被叫做用户自定义函数。
举例:
#!/usr/bin/python3 # 计算面积函数(自定义) def area(width, height): return width * height
# 打印问候(自定义) def print_welcome(name): print("Welcome", name)
print_welcome("Runoob") w = 4 h = 5 # 打印(内建函数) print("width =", w, " height =", h, " area =", area(w, h))
参数传递
在 python 中,类型属于对象,变量是没有类型的:
#!/usr/bin/python3 #可写函数说明 def printinfo( name, age ): "打印任何传入的字符串" print ("名字: ", name); print ("年龄: ", age); return; #调用printinfo函数 printinfo( age=50, name="runoob" );
以上实例输出结果:
名字: runoob
年龄: 50
默认参数
调用函数时,如果没有传递参数,则会使用默认参数。以下实例中如果没有传入 age 参数,则使用默认值:
#!/usr/bin/python3 #可写函数说明 def printinfo( name, age = 35 ): "打印任何传入的字符串" print ("名字: ", name); print ("年龄: ", age); return; #调用printinfo函数 printinfo( age=50, name="runoob" ); print ("------------------------") printinfo( name="runoob" );
输出结果:
名字: runoob 年龄: 50 ------------------------ 名字: runoob 年龄: 35
不定长参数
你可能需要一个函数能处理比当初声明时更多的参数。这些参数叫做不定长参数,和上述2种参数不同,声明时不会命名。基本语法如下
加了星号(*)的变量名会存放所有未命名的变量参数。如果在函数调用时没有指定参数,它就是一个空元组。我们也可以不向函数传递未命名的变量。如下实例:
#!/usr/bin/python3 # 可写函数说明 def printinfo( arg1, *vartuple ): "打印任何传入的参数" print ("输出: ") print (arg1) for var in vartuple: print (var) return; # 调用printinfo 函数 printinfo( 10 ); printinfo( 70, 60, 50 );
以上实例输出结果:
输出: 10 输出: 70 60 50
变量作用域
Python 中,程序的变量并不是在哪个位置都可以访问的,访问权限决定于这个变量是在哪里赋值的。
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称。Python的作用域一共有4种,分别是:
- L (Local) 局部作用域
- E (Enclosing) 闭包函数外的函数中
- G (Global) 全局作用域
- B (Built-in) 内建作用域
以 L –> E –> G –>B 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。
x = int(2.9) # 内建作用域 B g_count = 0 # 全局作用域 G def outer(): o_count = 1 # 闭包函数外的函数中 E def inner(): i_count = 2 # 局部作用域 L
Python 中只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,如下代码:
>>> if True: ... msg = 'I am from Runoob' ... >>> msg 'I am from Runoob' >>>
实例中 msg 变量定义在 if 语句块中,但外部还是可以访问的。
如果将 msg 定义在函数中,则它就是局部变量,外部不能访问:
>>> def test(): ... msg_inner = 'I am from Runoob' ... >>> msg_inner Traceback (most recent call last): File "<stdin>", line 1, in <module> NameError: name 'msg_inner' is not defined >>>
从报错的信息上看,说明了 msg_inner 未定义,无法使用,因为它是局部变量,只有在函数内可以使用。
全局变量和局部变量
定义在函数内部的变量拥有一个局部作用域,定义在函数外的拥有全局作用域。
局部变量只能在其被声明的函数内部访问,而全局变量可以在整个程序范围内访问。调用函数时,所有在函数内声明的变量名称都将被加入到作用域中。如下实例:
#!/usr/bin/python3 total = 0; # 这是一个全局变量 total2 = 0; # 这是一个全局变量 # 可写函数说明 def sum( arg1, arg2 ): #返回2个参数的和." total = arg1 + arg2; # total在这里是局部变量. print ("函数内是局部变量 : ", total) global total2 total2 = arg1 + arg2; # total在这里是全局变量. return total; #调用sum函数 sum( 10, 20 ); print ("函数外是全局变量 : ", total) print ("函数外是全局变量2 : ", total2)
以上实例输出结果:
函数内是局部变量 : 30
函数外是全局变量 : 0
函数外是全局变量2 : 30
如果要修改嵌套作用域(enclosing 作用域,外层非全局作用域)中的变量则需要 nonlocal 关键字了,如下实例:
#!/usr/bin/python3 def outer(): num = 10 def inner(): nonlocal num # nonlocal关键字声明 num = 100 print(num) inner() print(num) outer()
以上实例输出结果:
100 100
另外有一种特殊情况,假设下面这段代码被运行:
#!/usr/bin/python3 a = 10 def test(): a = a + 1 print(a) test()
以上程序执行,报错信息如下:
Traceback (most recent call last): File "test.py", line 7, in <module> test() File "test.py", line 5, in test a = a + 1 UnboundLocalError: local variable 'a' referenced before assignment
错误信息为局部作用域引用错误,因为 test 函数中的 a 使用的是局部,未定义,无法修改。
其他实际问题:
1、默认参数必须放在最后面,否则会报:
SyntaxError: non-default argument follows default argument
# 可写函数说明 def printinfo( age=35,name): # 默认参数不在最后,会报错 "打印任何传入的字符串" print("名字: ", name); print("年龄: ", age); return;
2、把N个关键字参数转化为字典:
>>> def func(country,province,**kwargs): ... print(country,province,kwargs) ... >>> func("China","Sichuan",city = "Chengdu", section = "JingJiang") China Sichuan {'city': 'Chengdu', 'section': 'JingJiang'} >>>
3、匿名函数也是可以使用"关键字参数"进行参数传递:
>>> g= lambda x,y : x**2+y**2 >>> g(2,3) 13 >>> g(y=3,x=2) 13
lambda 匿名函数也可以设定默认值
>>> g= lambda x=0,y=0 : x**2+y**2 >>> g(2,3) 13 >>> g(2) 4 >>> g(y=3) 9
4、对于变量作用域,变量的访问以 L(Local) –> E(Enclosing) –> G(Global) –>B(Built-in) 的规则查找,即:在局部找不到,便会去局部外的局部找(例如闭包),再找不到就会去全局找,再者去内建中找。
观察以下几个例子,均从内部函数输出变量 x:
1. 局部作用域
x = int(3.3) x = 0 def outer(): x = 1 def inner(): x = 2 print(x) inner() outer()
执行结果为 2,因为此时直接在函数 inner 内部找到了变量 x。
2.闭包函数外的函数中
x = int(3.3) x = 0 def outer(): x = 1 def inner(): i = 2 print(x) inner() outer()
执行结果为 1,因为在内部函数 inner 中找不到变量 x,继续去局部外的局部——函数 outer 中找,这时找到了,输出 1。
3.全局作用域
x = int(3.3) x = 0 def outer(): o = 1 def inner(): i = 2 print(x) inner() outer()
执行结果为 0,在局部(inner函数)、局部的局部(outer函数)都没找到变量 x,于是访问全局变量,此时找到了并输出。
4. 内建作用域
x = int(3.3) g = 0 def outer(): o = 1 def inner(): i = 2 print(x) inner() outer()
5、函数也可以以一个函数为其参数:
def hello () : print ("Hello, world!") def execute(f): "执行一个没有参数的函数" f() execute(hello)
输出:
Hello, world!
结束!