python之函数

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了python之函数相关的知识,希望对你有一定的参考价值。

防伪码:忘情公子著


函数是Python为了代码最大程度地重用和最小化代码冗余而提供的基本程序结构。

函数是一种设计工具,能让程序员将复杂的系统分解为可管理的部件,在需要时能够按需去调用这些部件。

函数用于将相关功能打包并参数化

在Python中可以创建4种函数:

 全局函数:定义在模块中

  局部函数:嵌套于其它函数中

  lambda(匿名)函数:仅是一个表达式,可以出现在任何位置,使用的灵活度比函数强得多。它生成一个函数对象,若想多次调用,则应将其赋予某变量名进行调用

  方法:与特定数据类型关联的函数,并且只能与数据类型关联一起使用。说白了就是定义在类(class)中的函数


创建函数,语法如下:

def functionName(parameters):
    suite

def是一个可执行语句,因此可以出现在任何能够使用语句的地方,甚至可以嵌套于其它语句,例如if或while中。

def创建了一个对象并将其赋值给一个变量名(即函数名)。

return用于返回结果对象,其为可选;无return语句的函数自动返回None对象。返回多个值时,彼此间使用逗号分隔,且组合为元组形式返回一个对象。

def语句运行之后,可以在程序中通过函数后附加括号进行调用。如:

In [1]: def printName():    #定义一个函数printName
   ...:     print "hello"
   ...: 

In [2]: printName()         #调用函数printName
hello


Python创建、改变或查找变量名,都是在名称空间中进行的。名称空间(作用域)说白了就是一个变量所能够生效的范围。

在Python中,变量名在程序代码中被赋值的位置,决定了其能够被访问到的范围。

函数定义了本地作用域,而模块定义了全局作用域

  每个模块都是一个全局作用域,因此,全局作用域的范围仅限于单个文件;

  每次对函数的调用都会创建一个新的本地作用域,赋值的变量除非声明为全局变量,否则均为本地变量;

  所有的变量名都可以归纳为本地、全局或内置的(由__builtin__模块提供)


变量名引用分三个作用域进行:首先是本地、之后是函数内、接着是全局,最后是内置。

技术分享

变量名解析遵循由内而外的法则,也即LEGB原则(如上图)。变量解析时有几点需要注意:

  先从Local(function)中查找,找到则返回解析结果,若找不到则到Enclosing function locals中查找;

  若在Enclosing function locals中找到了则返回解析结果,若找不到则到Global(module)中查找;

  若在Global(module)中找到了则返回解析结果,若找不到则到Built-in中查找;

  若在Built-in中找到了则返回解析结果,若找不到则返回“名称引用错误”异常

变量名解析时,作用域越小,其优先级越高。也就是说,若在Local(function)中找到了,则直接返回其解析结果,而不会再到Enclosing function locals上去查找了。


全局变量:

  全局变量是模块文件内部的顶层变量名;

  如果要在函数内部对全局变量进行赋值的话,必须事先使用global进行声明,global关键字后跟一个或多个由逗号隔开的变量名;

  全局变量名在函数内部不经声明也可以被引用;

  本地变量在函数返回时会消失,而全局变量不会,因此,使用全局变量是保存函数状态信息的最直接办法;

  尽量避免在函数中使用global声明全局变量。


内嵌函数:

  Python中函数可以嵌套,也即可以在一个函数内部定义一个函数;

  在函数内部定义的函数仅能由外层函数进行调用;

  而如果外层函数直接把内层函数使用return返回,则调用外层函数时赋值的变量名引用的是一个内层函数对象,且此内层函数能够记忆其内部引用的外层函数的变量,这种行为叫做工厂函数,也叫闭合函数

In [11]: def maker(N):
    ...:     def action(X):
    ...:         return X ** N
    ...:     return action
    ...:

In [12]: f = maker(2)

In [13]: f(3)
Out[13]: 9

In [14]: f(4)
Out[14]: 16

In [15]: type(f)
Out[15]: function


参数传递:

  参数的传递是通过自动将对象赋值给本地变量实现的

技术分享

  不可变参数通过“值”进行传递,在函数内部改变形参的值,只是让其引用了另一个对象(如数字)

  可变参数通过“指针”进行传递,在函数内部改变形参的值,将直接修改引用的对象(如列表)


有两种方式可避免可变参数被函数修改:

  1、直接传递可变对象的副本:

In [16]: L = [1,2,3,4]

In [17]: def changer(X):
    ...:     X[2]+=10
    ...:     return X
    ...:

In [18]: changer(L[:])
Out[18]: [1, 2, 13, 4]

In [19]: print L
[1, 2, 3, 4]

  2、在函数内部创建可变参数的副本

In [27]: L = [1,2,3,4]

In [28]: def changer(X):
    ...:     aa = X[:]
    ...:     aa[2]+=10
    ...:     return aa
    ...:

In [29]: changer(L)
Out[29]: [1, 2, 13, 4]

In [30]: print L
[1, 2, 3, 4]


参数匹配模型:

默认情况下,参数通过其位置进行传递,从左至右,这意味着,必须精确地传递和函数头部参数一样多的参数

但也可以通过关键字参数、默认参数或参数容器等改变这种机制

  位置:从左至右

  关键字参数:使用“name=value”的语法通过参数名进行匹配

  默认参数:定义函数时使用“name=value”的语法直接给变量一个值,从而传入的值可以少于参数个数

  可变参数:定义是为了整合,调用是为了分解

    定义函数时使用*开头的参数,可用于收集任意多基于位置的参数:

In [31]: def test(*x):
    ...:     print x
    ...: 

In [32]: test(1)
(1,)

In [33]: test(1,2,3)
(1, 2, 3)

    定义函数时使用**开头的参数,可用于收集任意多基于关键字参数,并将其转换成字典:

In [34]: def dict(**x):
    ...:     print x
    ...: 

In [35]: dict(x=1,y=2,z=6)
{‘y‘: 2, ‘x‘: 1, ‘z‘: 6}

   混用位置参数与可变参数:

In [36]: def a(x,*y):
    ...:     print x,y
    ...: 

In [37]: a(1,2,3,4)
1 (2, 3, 4)
In [38]: def b(*x,**y):
    ...:     print x
    ...:     print y
    ...: 

In [39]: b(1,2,3,4,5,i=3,j=9,c=5)
(1, 2, 3, 4, 5)
{‘i‘: 3, ‘c‘: 5, ‘j‘: 9}

  可变参数解包:调用函数时,使用*开头的参数,可用于将参数集合打散,从而传递任意多基于位置或关键字的参数。可以理解为分解参数。

   变量分解赋值:

In [1]: l1 = [‘Sun‘,‘Mon‘,‘Tue‘]

In [2]: x,y,z = l1

In [3]: print x
Sun

In [4]: print y
Mon

In [5]: print z
Tue
In [6]: l2 = [‘Sun‘,‘Mon‘,‘Tue‘]

In [7]: def a(x,y,z):
   ...:     print x,y,z
   ...: 

In [8]: a(*l2)
Sun Mon Tue

可变参数与位置参数混合使用时,不论是定义还是调用,均使用以下顺序:

  位置参数-->任意位置参数(*)-->关键字参数(**)


匿名函数lambda:

语法如下:

lambda args: expression

  args:以逗号分隔的参数列表

  expression:用到args中各参数的表达式

lambda语句定义的代码必须是合法的表达式,不能出现多条件语句(可使用if的三元表达式)和其它非表达式语句,如for和while等。

lambda的首要用途是指定短小的回调函数。lambda将返回一个函数而不是将函数赋值给某变量名。

注意:

  lambda是一个表达式而非语句;

  lambda是一个单个表达式,而不是一个代码块

In [9]: lambda x,y: print x,y    #不能是语句,只能是表达式
  File "<ipython-input-9-323c5186b793>", line 1
    lambda x,y: print x,y
                    ^
SyntaxError: invalid syntax


In [10]: lambda x,y: x + y        #返回的是一个函数
Out[10]: <function __main__.<lambda>>

因为lambda返回的是一个函数,所以如果要调用它的话,则要将lambda表达式赋予一个变量名,通过变量名来调用:

In [11]: a = lambda x,y: x + y

In [12]: a(5,6)
Out[12]: 11

正因为lambda函数调用时必须赋予给某个变量名,通过变量名来调用,而这个变量名又不固定,故此称之为匿名函数。

def语句创建的函数将赋值给某变量名,而lambda表达式则直接返回函数。lambda也支持使用默认参数。

In [13]: def testFunc(x,y,z):
    ...:     return x + y + z
    ...:

In [14]: testFunc(4,5,6)
Out[14]: 15

In [15]: f = lambda x,y,z: x+y+z

In [16]: f(4,5,6)
Out[16]: 15

In [17]: f2 = (lambda x,y,z=10: x+y+z)

In [18]: f2(4,5)
Out[18]: 19

在对某个数据对象作出多种不同处理时,可以把每一种处理机制定义成一个lambda,而后对这个数据对象调用这多个lambda表达式。

In [1]: l3 = [ (lambda x: x*2),(lambda y: y*3) ]

In [2]: for i in l3:        #i取到的是lambda表达式,而不是x和y的值
   ...:     print i(4)
   ...: 
8
12


本文出自 “忘情博” 博客,请务必保留此出处http://itchentao.blog.51cto.com/5168625/1884653

以上是关于python之函数的主要内容,如果未能解决你的问题,请参考以下文章

python调试之pdb调试工具

前端面试题之手写promise

Flask之模板之宏继承包含

13 个非常有用的 Python 代码片段

在 Python 多处理进程中运行较慢的 OpenCV 代码片段

python使用上下文对代码片段进行计时,非装饰器