出自:https://blog.csdn.net/gavin_john/article/details/50018297
函数相关的语句和表达式
语句 | 例子 |
Calls | myfunc("spam","eggs",meat=ham) |
def | def adder(a,b=1,*C): |
return | return a+b+c[0] |
global | def changer(): global x;x = 'new' |
nonlocal | def changer(): nonlocal x;x = 'new' |
yield | def squares(x): for i in range(x):yield i**2 |
lambda | Funcs=[lambda x:x**2,lambda x:x*3] |
======================================================================
为何使用函数
函数是一个通用的程序结构的部件,它的作用为:
(1)最大化的代码重用和最小化的代码冗余
(2)流程的分解
======================================================================
编写函数
(1)def是可执行的代码。
函数并不存在,直到运行了def后才存在。事实上,在if语句、while循环甚至是其他的def中嵌套式合法的。
在典型的操作中,def语句在模块文件中编写,并自然而然地在模块文件第一次被导入的时候生成定义的函数。
(2)def创建了一个对象并将其赋值给某一变量名。
当Python运行到def语句时,它将会生成一个新的函数对象并将其赋值给这个函数名。就像所有的赋值一样,函数名变成了某一个函数的引用
函数也可以通过lambda表达式来创建
(3)lambda创建一个对象但将其作为结果返回
也可以用lambda表达式创建函数,这一功能允许我们把函数定义内联到语法上一条def语句不能工作的地方。
(4)return将一个结果对象发送给调用者。
(5)yield向调用者发回一个结果对象,但是记住它离开的地方。
像生成器这样的函数也可以通过yield语句来返回值,并挂起它们的状态以便稍后能过恢复状态
(6)global声明了一个模块级的变量并被赋值。
在默认情况下,所有在一个函数中被赋值的对象,是这个函数的本地变量,并且仅在这个函数运行的过程中存在。
为了分配一个可以在整个模块中都可以使用的变量名,函数需要在global语句中将它列举出来。
通常情况下,变量名往往需要关注它的作用域(也就是说变量存储的地方)
(7)nonlocal声明了将要赋值的一个封闭的函数变量。
(8)函数是通过赋值(对象引用)传递的。
在Python中,参数通过赋值传递给了函数(也就是说,就像我们所学过的,使用对象引用)
(9)参数、返回值以及变量并不是声明
---------------------------------------------------------------------------------------------------------------------------------
def语句
def语句将创建一个函数对象并将其赋值给一个变量名。一般格式如下:
- def <name>(arg1,arg2,...,argN):
- <statements>
def首行定义了函数名,赋值给了函数对象,并在括号中包含了0个或以上的参数。在函数调用的时候,在首行的参数名赋值给了括号中的传递来的对象。
函数的主体往往都包含了一条return语句。
- def<name> (arg1,arg2,...,argN):
- ...
- return <value>
从技术角度来讲,一个没有返回值的函数自动返回了none对象,但是这个值是往往被忽略掉的
函数也许会有yield语句,这在每次都会产生一系列值时被用到。
---------------------------------------------------------------------------------------------------------------------------------
def 语句是实时执行的
Python的def语句实际上是一个可执行语句:当它运行的时候,它创建一个新的函数对象并将其赋值给一个变量名。(请记住,Python中所有的语句都是实时运行的,没有像独立的编译时间这样的流程)因为它是一个语句,一个def往往是包含在模块文件中,并在模块导入时运行,函数还是可以通过嵌套在if语句中去实现不同的函数定义,这样也是完全合法的。
- if test:
- def func():
- ...
- else:
- def func():
- ...
- ...
- func()
因为函数定义是实时发生的,所以对于函数名来说并没有什么特别之处。关键之处在于函数名所引用的那个对象。
- otername = func
- otername()
实际上,除了调用之外,函数允许任意的属性附加到记录信息以供随后使用:
- def func():...
- func()
- func.attr = value
第一个例子:定义和调用
【定义】
这是一个在交互模式下输入的定义语句,它定义了一个名为times的函数,这个函数将返回两个参数的结果.
- >>> def times(x,y):
- return x*y
---------------------------------------------------------------------------------------------------------------------------------
【调用】
在def运行之后,可以在程序中通过函数名后增加括号调用(运行)这个函数。括号中可以包含一个或多个对象参数,这些参数将会传递给函数头部的参数名。
- >>> times(2,6)
- 12
如果稍后我们需要使用这个值,可以将其赋值给另一个变量。例如:
- >>> x = times(3,6)
- >>> x
- 18
- >>> times('Hello',3)
- 'HelloHelloHello'
---------------------------------------------------------------------------------------------------------------------------------
Python中的多态
就像上边那样,times函数的表达式x*y的意义完全取决于x和y的对象类型。Python将一对象在某种语法的合理性交由对象自身来判断。
这种依赖类型的行为成为多态,其含义就是一个操作的意义取决于被操作对象的类型。
======================================================================
第二个例子:寻找序列的交集
【定义】
把代码封装在函数中,使他成为一个通用搜索交集的工具
- >>> def intersect(seq1,seq2):
- res = []
- for x in seq1:
- if x in seq2:
- res.append(x)
- return res
【调用】
在你能够使用函数之前,必须先创建它。你可以先运行def语句,要么就是通过在交互模式下输入,要么就是在一个模块文件中编写好它,然后导入这个文件。一旦运行了def,就可以通过在括号中传递两个序列对象从而调用这个函数:
- >>> s1 = 'gavin'
- >>> s2 = 'canv'
- >>> intersect(s1,s2)
- ['a', 'v', 'n']
实际上,这个函数可以用一个单独的列表解析表达式来替代
- >>> [x for x in s1 if x in s2]
- ['a', 'v', 'n']
重访多态
和所有的Python中的函数一样,intersect是多态的,也就是说,它可以支持多种类型,只要其支持扩展对象接口:
- >>> x = intersect([1,2,3],(1,4))
- >>> x
- [1]
对于intersect函数,这意味着第一个参数必须支持for循环,并且第二个参数支持成员测试。所有满足这两点的对象都能够正常工作,与它们的类型无关。
---------------------------------------------------------------------------------------------------------------------------------
本地变量
可能上面的intersect函数最有趣的部分是其名称。它证明了,intersect函数中的res变量在Python中叫做本地变量——这个变量只是在def内部的函数中是可见的,并且仅在函数运行时是存在的。实际上,intersect函数内的所有的变量均为本地变量。