1.函数创建
1).函数代码块以def关键词开头,后接函数标识符名称和圆括号()
2).任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数
3).函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明
4).函数内容以冒号起始,并且缩进
5).Return[expression]结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回
None
def functionname( parameters ): "函数_文档字符串" function_suite return [expression]
2.函数参数
形参:写在def语句中函数名后面的变量通常叫做函数的形式参数,
实参:而调用函数的时候提供的值是实际参数,或者称为参数; 参数存储在局部作用域(local scope)内。
2.1 参数的改变:在函数内为参数赋予新值不会改变外部任何变量的值。
-
def try_to_change(n): n = 'Mr. Gumby' name = 'Mrs Entity' try_to_change(name) print name
运行结果打印"Mrs Entity“。在try_to_change内,参数n获得了新值,但是它没有影响到name变量。n实际上是个完全不同的变量。
2.2关键字参数:通常我们所使用的参数都叫做位置参数,因为它们的位置很重要——事实上比它们的名字更重要。因此python引入了使用参数名来提供参数,这类使用参数名提供参数就叫做关键字参数。
def hello_1(greeting,name): print '%s, %s!' %(greeting,name) def hello_2(name,greeting): print '%s, %s!' %(name,greeting) print hello_1('hello','world') print hello_2('hello','world')
#运行结果:
- hello, world
- None
- hello, world
- None
-
def hello_1(greeting,name): print '%s, %s!' %(greeting,name) def hello_2(name,greeting): print '%s, %s!' %(name,greeting) hello_1(greeting='hello',name='world') hello_1(name='world',greeting='hello')
#结果:- hello, world
- hello, world
2.3 参数的默认值:前面提到了关键字参数的一些作用,但关键字参数最厉害的地方在于可以在函数中给参数提供默认值:
def hello_3(greeting='Hello',name='world'): print '%s, %s!' %(greeting,name) hello_3() hello_3('greeting') hello_3('greeting','universe')
#结果:
- Hello, world!
- greeting, world!
- greeting, universe!
def test(): print 'This is printed' return print 'This is not' x = test() print x #运行结果: This is printed None
1 #coding:utf-8 #设置python文件的编码为utf-8,这样就可以写入中文注释 2 def foo(arg1,*tupleArg,**dictArg): 3 print "arg1=",arg1 #formal_args 4 print "tupleArg=",tupleArg #() 5 print "dictArg=",dictArg #[] 6 foo("formal_args")
tupleArg前面“*”表示这个参数是一个元组参数,从程序的输出可以看出,默认值为();
dicrtArg前面有“**”表示这个字典参数(键值对参数)。
可以把tupleArg、dictArg看成两个默认参数。多余的非关键字参数,函数调用时被放在元组参数tupleArg中;多余的关键字参数,函数调用时被放字典参数dictArg中。
1 #coding:utf-8 #设置python文件的编码为utf-8,这样就可以写入中文注释 2 def foo(arg1,arg2="OK",*tupleArg,**dictArg): 3 print "arg1=",arg1 4 print "arg2=",arg2 5 for i,element in enumerate(tupleArg): 6 print "tupleArg %d-->%s" % (i,str(element)) 7 for key in dictArg: 8 print "dictArg %s-->%s" %(key,dictArg[key]) 9 10 myList=["my1","my2"] 11 myDict={"name":"Tom","age":22} 12 foo("formal_args",arg2="argSecond",a=1) 13 print "*"*40 14 foo(123,myList,myDict) 15 print "*"*40 16 foo(123,rt=123,*myList,**myDict)
输出为:
从上面的程序可以看出:
(1)如代码第16行。
参数中如果使用“*”元组参数或者“**”字典参数,这两种参数应该放在参数列表最后。并且“*”元组参数位于“**”字典参数之前。
关键字参数rt=123,因为函数foo(arg1,arg2="OK",*tupleArg,**dictArg)中没有rt参数,所以最后也归到字典参数中。
(2)如代码第14行。
元组对象前面如果不带“*”、字典对象如果前面不带“**”,则作为普通的对象传递参数。
多余的普通参数,在foo(123,myList,myDict)中,123赋给参数arg1,myList赋给参数arg2,多余的参数myDict默认为元组赋给myList。
在Python中定义函数,可以用必选参数、默认参数、可变参数和关键字参数,这4种参数都可以一起使用,或者只用其中某些,但是请注意,参数定义的顺序必须是:必选参数、默认参数、可变参数,关键字参数。
def func(a, b, c=0, *args, **kw): print 'a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw
在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。
>>> func(1, 2) a = 1 b = 2 c = 0 args = () kw = {} >>> func(1, 2, c=3) a = 1 b = 2 c = 3 args = () kw = {} >>> func(1, 2, 3, 'a', 'b') a = 1 b = 2 c = 3 args = ('a', 'b') kw = {} >>> func(1, 2, 3, 'a', 'b', x=99) a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
最神奇的是通过一个tuple和dict,你也可以调用该函数:
>>> args = (1, 2, 3, 4) >>> kw = {'x': 99} >>> func(*args, **kw) a = 1 b = 2 c = 3 args = (4,) kw = {'x': 99}
所以,对于任意函数,都可以通过类似func(*args, **kw)
的形式调用它,无论它的参数是如何定义的。
*args
是可变参数,args接收的是一个tuple;
**kw
是关键字参数,kw接收的是一个dict。
参数既可以直接传入:func(1, 2, 3)
,又可以先组装list或tuple,再通过*args
传入:func(*(1, 2, 3))
;
关键字参数既可以直接传入:func(a=1, b=2)
,又可以先组装dict,再通过**kw
传入:func(**{'a': 1, 'b': 2})
。
3. 作用域
3.1作用域分类
python中的作用域分4种情况:搜索变量的优先级顺序依次是:作用域局部>外层作用域>当前模块中的全局>python内置作用域,也就是LEGB。
L:local,局部作用域,即函数中定义的变量;
E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
G:globa,全局变量,就是模块级别定义的变量;
B:built-in,系统固定模块里面的变量,比如int, bytearray等。
1 x = int(2.9) # int built-in 2 3 g_count = 0 # global 4 def outer(): 5 o_count = 1 # enclosing 6 def inner(): 7 i_count = 2 # local
3.2 作用域的产生
在Python中,只有模块(module),类(class)以及函数(def、lambda)才会引入新的作用域,其它的代码块(如if、try、for等)是不会引入新的作用域的,如下代码:
if True: x = 1; print(x) # 1
这个是没有问题的,if并没有引入一个新的作用域,x仍处在当前作用域中,后面代码可以使用。
def test(): x2 = 2 print(x2) # NameError: name 'x2' is not defined
3.3 变量的修改
一个不在局部作用域里的变量默认是只读的,如果试图为其绑定一个新的值,python认为是在当前的局部作用域里创建一个新的变量,也就是说在当前局部作用域中,如果直接使用外部作用域的变量,那么这个变量是只读的,不能修改,如:
1 count = 10 2 def outer(): 3 print(count) 4 count = 100 5 print(count) 6 outer() 7 #UnboundLocalError: local variable 'count' referenced before assignment
这里第一个print中,使用到了外部作用域的count,这样后面count就指外部作用域中的count了,再修改就会报错。 如果没使用过这个变量,而直接赋值,会认为是新定义的变量,此时会覆盖外部作用域中变量,如:
1 count = 10 2 def outer(): 3 count = 100 4 print(count) 5 outer() 6 #100
内部作用域中直接声明了count=100,后面使用count都是内部作用域的了。
3.4 global关键字
当内部作用域想修改外部作用域的变量时,就要用到global和nonlocal关键字了,当修改的变量是在全局作用域(global作用域)上的,就要使用global先声明一下,代码如下:
1 count = 10 2 def outer(): 3 global count 4 print(count) 5 count = 100 6 print(count) 7 outer() 8 #10 9 #100
3.5 nonlocal关键字
global关键字声明的变量必须在全局作用域上,不能嵌套作用域上,当要修改嵌套作用域(enclosing作用域,外层非全局作用域)中的变量怎么办呢,这时就需要nonlocal关键字了
1 def outer(): 2 count = 10 3 def inner(): 4 nonlocal count 5 count = 20 6 print(count) 7 inner() 8 print(count) 9 outer() 10 #20 11 #20
3.6 小结:
(1)变量查找顺序:LEGB,作用域局部>外层作用域>当前模块中的全局>python内置作用域;
(2)只有模块、类、及函数才能引入新作用域;
(3)对于一个变量,内部作用域先声明就会覆盖外部变量,不声明直接使用,就会使用外部作用域的变量;
(4)内部作用域要修改外部作用域变量的值时,全局变量要使用global关键字,嵌套作用域变量要使用nonlocal关键字。nonlocal是python3新增的关键字,有了这个关键字,就能完美的实现闭包了。