python基础教程总结5——函数

1.函数创建

1).函数代码块以def关键词开头,后接函数标识符名称和圆括号()
2).任何传入参数和自变量必须放在圆括号中间。圆括号之间可以用于定义参数
3).函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明
4).函数内容以冒号起始,并且缩进
5).Return[expression]结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None

def functionname( parameters ):
   "函数_文档字符串"
   function_suite
   return [expression]

 

 

2.函数参数

  形参:写在def语句中函数名后面的变量通常叫做函数的形式参数,

  实参:而调用函数的时候提供的值是实际参数,或者称为参数;      参数存储在局部作用域(local scope)内。


2.1 参数的改变:在函数内为参数赋予新值不会改变外部任何变量的值。

  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')

#运行结果:
  1. hello, world
  2. None
  3. hello, world
  4. None

 

  1. 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')

    #结果:
    1. hello, world
    2. 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')
#结果:
  1. Hello, world!
  2. greeting, world!
  3. greeting, universe!


 

 
2.4 并非真正函数的函数:数学意义上的函数,总在计算其参数后返回点什么。python的有些函数却并不返回任何东西。

def test():
    print 'This is printed'
    return
    print 'This is not'
x = test()
print x
#运行结果:
This is printed
None
 
  这里的return语句只起到结束函数的作用,第二个print语句被跳过了。return语句不返回任何值,那么x又引用什么呢?对,就是第二行的None。所以,所有的函数其实都返回了东西:当不需要它们返回值的时候,它们就返回None。

 
2.5 可变长度参数
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。

 
 
2.6 参数顺序

  在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新增的关键字,有了这个关键字,就能完美的实现闭包了。

 

posted @ 2015-07-14 20:30  zxqstrong  阅读(377)  评论(0编辑  收藏  举报