python笔记之函数

来源:互联网 发布:淘宝查看自己的评价星 编辑:程序博客网 时间:2024/05/17 06:14
1. 函数创建
Python中的函数都是通过def语句来定义的,def的一般格式如下所示。
def <name>([arg1,arg2,...argN]):
    <statements>
这里不需要声明函数的返回类型和参数类型,动态类型语言会根据参数具体的类型来进行相应的操作。如果参数传入的对象没有相应操作的实现接口则会抛出异常。
statements为函数体,而函数主体一般都会包含一条return语句,表示函数调用的结束,并将结果返回至调用处。如果没有return语句,函数在执行完成以后会自动返回None对象,不过这个一般都是被忽略的。
 
python中的def语句实际上是一个可执行的语句,所以它可以出现在任意语句可以出现的地方,甚至是嵌套在其他语句中。
if test:    def func():        …else:    def func():        ……func() 
python中的函数定义是实时发生的,在运行def之前,函数是不存在的,直到运行def的时候才会创建一个新的函数对象并将其赋值给函数名,所以函数本身只是一个对象。既然函数是对象,那么对于函数名来说就没有什么特别之处,将其赋给另外一个变量后通过另外一个变量也是可以调用的,关键之处在于函数名所引用的那个对象。
>>> def func():print "hi"...  >>> func<function func at 0x7f0931a38a28>>>> type(func)<type 'function'>>>> f = func>>> f()hi>>> f == funcTrue>>> f is funcTrue 

2. 作用域
python中变量名解析遵循LEGB原则,即对于一个def定义的函数,变量名会搜索四个作用域:本地作用域L,之后是上一层结构中的函数定义语句的本地作用域,也叫外部作用域E,然后是全局作用域G,最后是内置作用域B,并且在第一处找到的地方停下来。如果变量没有搜索到,则抛出异常。
当在一个函数中给一个变量赋值的时候,python总是创建或改变本地作用域的变量名,除非这个变量已经被声明为全局变量。
当在函数之外给一个变量赋值的时候,本地作用域与全局作用域是相同的。
a = 1def func():    b = 2    print "a in func():%d" %a    print "b in func():%d" %b    def func2():        c = 3        print "a in func2():%d" %a        print "b in func2():%d" %b        print "c in func2():%d" %c    func2()func()print "a in global: %d" %a
我们从最里层说起,在func2()中,因为它是嵌套在函数func()中的,(这种函数中定义函数的行为在C语言中是绝对不允许的。)变量c是在func2()中定义的,所以他的作用域就是func2()的本地作用域,外部是不能使用的,只能内部或者再次嵌套的函数中可以使用;而变量b是在func()中定义的,它属于func()的本地作用域,而func的本地作用域正是func2()的外部作用域,所以在func2()中可以使用变量b;a由于是在函数之外定义的,它的本地作用域就是全局作用域,因为它可以成为是全局变量,在本文件的任何位置都能使用。print语句就不用多说了吧,内置作用域中定义的,所以任何位置任何文件都能使用。
作用域都是从本地作用域依次往外部搜索的,所以内嵌的作用域中的内容在外部是无法使用的,func()就不能直接使用变量c,全局区就不能直接使用变量b和函数func2(),而且如果搜索到的变量不属于本作用域,这个变量当前就只能读,不能修改。比如func()中就不能修改a,func2()中就不能修改a和b,注意这里的修改不是使用”=”,因为“=”是赋值,就相当在当前的命令空间中增了一个变量,而不是使用外部的变量。
a = 1def func():    a += 1func()print aUnboundLocalError: local variable 'a' referenced before assignment 
总结一句话,外部看不见内部的东西,内部可以看见外部的东西,但是不能改。
 
需要注意的地方就是只有def(包括lambada语句)和后面创建类的class语句才会创建自己对应的本地作用域,if、while、for都不会新建作用域。导入的模块都是全局作用域,全局作用域的的作用范围仅限于单个文件。
 
global语句用来声明一个或多个全局变量,global语句包含了关键字global,其后跟一个或多个用逗号分开的变量名。如果全局变量是在函数内部被赋值或者被修改的话,必须经过声明,否则会变成函数自己的内部变量或者报错;如果只是引用则不需要global声明。
a = 1def func():    global a    a += 1func()print a a = 1def func():    global a    a = 2    print "a in func():%d" %afunc()print a
3.0中新增的nonlocal语句可以实现于global类似的功能,不过不同之处是nonlocal声明的变量必须已经在一个def中被赋值过,也就是说nonlocal是在函数的二层或者更多嵌套中使用的。
def func():    a = 1    def func2():        nonlocal a        a += 1    func2()    print(a)func()
上述的例子中,用global也能实现,不过需要每次都对a进行global声明。
def func():     global a     a = 1     def func2():         global a         a += 1     func2()     print(a)func()


3. 参数

python中的函数传递是通过自动将对象赋值给本地变量名来实现的,比较特殊的地方是不可变参数是通过值传递,比如数字,字符串,元组;而可变参数则是通过‘指针’进行传递,列表,字典就能够在函数内部进行原处的修改。

函数参数的匹配都是从左至右进行匹配,在没有传递的时候可以设置默认值,可变参数是通过字符*开头来实现的。
*会将参数收集到一个元组中,而**则会将参数传递给一个新的字典。
def fun(a=1, b=2):    print a,bfun()fun(2)fun(2,3) def fun(*a):    print afun()fun(1,2)fun('a', 'b', 'c') def fun(**a):    print afun()fun(a=1, b=2)
在调用函数的时候使用*语法可以实现对参数的解包,这样就可以实现一个变量同时传入多个参数。
def fun(*a):    print al=[1,2]fun(l)fun(*l)
这种方法在编写脚本很难 预测传入参数个数的时候就比较方便,需要注意的就是*/**在函数定义的地方就表示收集任意数量的参数,而在调用的时候,则表示解包任意个数的参数。
 
4. 函数属性
python中的函数本身也是一种对象,所以函数有本身的一些属性和方法,而且可以向函数附加任意用户自定义的属性。
>>> def fun():print "hello"... >>> dir(fun) ['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']>>> fun.__name__'fun'>>> fun.count=0>>> dir(fun)['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'count', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']>>> fun.count0


5. 匿名函数 lambda

除了def之外,python还提供了一种生成函数对象的表达式lambda,这个表达式创建了一个能够调用的函数,但是他返回一个函数而不是将函数赋值给一个变量名,所以lambda也叫匿名函数。
lambda的一般格式是关键字lambda,之后一个或多个参数,紧跟一个冒号,最后是表达式:
lambda argument1,argument2,... :expression
lambda是一个表达式,而不是一个语句,所以它可以出现在不允许def出现的地方,比如列表和字典的成员或者函数调用的参数。

lambda的主体是一个单个的表达式,而不是代码块,所以不能包含其他语句,if、for、while都不能使用,不过可以调用其他函数。

>>> f = lambda x:x*x>>> f(2)4>>> f(3)9>>> l =[lambda x:x+x, lambda x:x*x]>>> for f in l:...     print(f(2))...  44>>> l[0](3)6>>> l[1](3)9  
 
6. map filter & reduce
1). 在序列中映射函数map
程序对列表或其他序列常常需要对每个元素进行一个操作并把结果集合起来,例如对列表l中每个元素都加1,按照以前的方法就需要使用for循环然后对每个元素进行操作,并逐一增加到一个新的列表中。
>>> L=[1,2,3,4,5]>>> add=[]>>> for i in L:...     add.append(i+1)...  >>> add [2, 3, 4, 5, 6]
或:
>>> add = [x+1 for x in L]>>> add[2, 3, 4, 5, 6]
现在我们可以使用python内置的函数map来完成这个操作:
>>> def fun(x):...     return x+1... >>> add=map(fun,L)>>> add [2, 3, 4, 5, 6]
或者:
>>> add=map(lambda x:x+1, L)>>> add[2, 3, 4, 5, 6] 
map的基本格式为:map(function, sequence[, sequence, ...])
对 sequence (s)的每个元素都执行函数function操作,如果有多个序列,并行进行操作,返回一个新的列表(3.0返回一个迭代器),若funciton为None,返回 sequences组成的列表。
>>> s1="abc">>> s2="123" >>> map(lambda x,y :x+y, s1, s2)['a1', 'b2', 'c3']>>> map(None, s1, s2)[('a', '1'), ('b', '2'), ('c', '3')]


2). filter

filter是基于某个测试函数来过滤掉不符合要求的一些元素。
基本格式为:filter(function or None, sequence)  
对 sequence每个元素执行function函数,如果函数返回真的话,将当前元素增加到返回结果中,返回的类型为sequence本身的类型。如果funcition为None,则返回序列本身。(3.0返回迭代器)。

 

3)reduce

基本格式为:reduce(function, sequence[, initial])
首先从序列中拿出前两个元素作为function的参数然后执行funtion,并将结果与序列的下一个元素作为function的两个参数再次执行function,依次类推,直到序列结束。若指定 initial则会将 initial放置为序列之前,可以理解为作为序列的第一个元素,从而当序列为空的时候充当默认返回结果。
reduce(lambda x,y :x+y, [1,2,3,4,5])执行的计算过程就是((((1+2)+3)+4)+5)
>>> reduce(lambda x,y :x+y, [1,2,3,4,5])15>>> reduce(lambda x,y :x+y, [1,2,3,4,5],1)16>>> reduce(lambda x,y :x+y, [1,2,3,4,5],10)25>>> reduce(lambda x,y :x+y, [],1)1 
3.0中已经将reduce从内置函数中移到模块functools中,使用时需要导入functools模块。
原创粉丝点击