Python中使用def关键字来声明函数,声明函数的格式为:html
def func_name(args): ...body... [return ...]
有3个须要注意的地方:python
return None
,即函数默认返回None结构若是函数体body语句只有一行,或者能够简写为一行,则能够写在def的同行。例如:express
def myfunc(x,y,z): print(x+y+z)
函数声明好以后,就能够执行函数,执行函数也称为调用函数,方式为func_name(args)
,例如:编程
myfunc(1,2,3)
函数中每每会包含一个return或多个return语句,它能够出如今函数中的任意位置处,它用来结束函数的执行,并返回给定的值。例如:数据结构
def func(x): return x+5
表示返回x+5
的值,返回值是一种值类型,因此能够赋值给变量、能够输出、能够操做等等。例如:闭包
print(func(3)) # 输出返回值 a=func(4) # 赋值给变量 print(a) print(func(5)+3) # 数值操做
return语句是可选的,若是函数中不指定return语句,则默认返回None,即相似于return None
。app
函数的参数其实也是变量,只不过这些变量是独属于函数的本地变量,函数外部没法访问。在函数调用的时候,会将给定的值传递给函数的参数,这其实是变量赋值的过程。编程语言
def myfunc(x,y,z): print(x,y,z) myfunc(1,2,3)
def首先声明好函数,而后到了myfunc(1,2,3)
时,表示调用函数(执行函数),调用函数时会将给定的值1,2,3
传递给函数的参数x,y,z
,其实就是变量赋值x=1,y=2,z=3
,而后使用print输出它们。函数
因为python是动态语言,无需先声明变量,也无需指定变量的类型,因此python的函数参数和返回值很是的灵活。任何类型的变量或数据结构均可以传递给参数,这其实是变量赋值的过程。例如:3d
myfunc(1,2,3) myfunc("abc",2,"def") myfunc([1,2,3],4,5)
上面几个函数调用语句中,赋值给参数的值能够是数值类型,能够是字符串类型,能够是列表类型,也能够是其它任何数据类型。
python函数的参数相比其它语言要复杂一些,意味着要灵活不少,短短一个小节的篇幅彻底无法解释清楚,关于参数细节,详细内容见后面的文章。
def用来声明一个函数,python的函数包括函数名称、参数、函数体、函数体中涉及到的变量、返回值。
实际上,函数名称实际上是一个变量名,def表示将保存在某块内存区域中的函数代码体赋值给函数名变量。例如:
def myfunc(x,y,z): ...CODE...
上面表示将函数体赋值给变量名myfunc。以下图:
既然是变量,就能够进行输出:
def myfunc(x): return x+5 print(myfunc)
输出结果:
<function myfunc at 0x032EA6F0>
因为python是解释型语言,因此必须先定义函数,才能调用函数。
若是导入一个模块文件,导入的时候会解释、执行文件中的代码,包括def语句,也就是说,导入文件时会先声明好函数。
请必定理解本节内容,也许细节方面可能会有些不许确,但对于深刻理解函数来讲(不只限于python语言),是很是有帮助的,特别是理解做用域规则的时候。
python是解释性语言,读一行解释一行,解释一行忘记一行。而函数是一种代码块,代码块是一个解释单元,是一个总体。在代码块范围内不会忘记读取过的行,也不会读一行就当即解释一行,而是读取完全部代码块内的行,而后统筹安排地进行解释。关于这一点,在后面的文章代码块详述中有很是详细的解释,建议一读。
当python读取到def所在行的时候,知道这是一个函数声明语句,它有一个属于本身的代码块范围,因而会读完整个代码块,而后解释这个代码块。在这个解释过程当中,会记录好变量以及该变量的所属做用域(是全局范围内的变量仍是函数的本地变量),但必定注意,def声明函数的过程当中不会进行变量的赋值(参数默认值除外,见下文),只有在函数调用的时候才会进行变量赋值。换句话说,在def声明函数的过程当中,在函数被调用以前,函数所记录的变量一直都是变量的地址,或者通俗一点理解为记录变量的名称,而不会进行变量的赋值替换。
实际上,变量的明确的值会看成常量被记录起来。如a=10
的10被做为常量,而变量a赋值给变量b时b=a
,a显然不会做为常量。
以下函数:
x=3 def myfunc(a,b): c=10 print(x,a,b,c) myfunc(5,6)
输出结果为:"3 5 6 10"。
上面的函数涉及到了4个变量:a、b、c、x。其中:
在def的过程当中,会完完整整地记录好这些变量以及所属做用域,但只会记录,不会进行变量的赋值。以下图:
而后函数被调用,这时候才会开始根据记录的做用域搜索变量是否存在,是否已经赋值(非本地变量),并对须要赋值的变量赋值:
a=5,b=6
,而后赋值普通的本地变量c=10
如图:
最后执行print(x,a,b,c)
输出这些变量的值。
还需注意,python是读一行解释一行的,在函数调用过程当中,由于c=10
在print()
的前面,因此是先赋值c=10
,再执行print,若是print在c=10
前面,则先执行print,再赋值,这显然是错误的,由于print()中使用了变量c,但目前尚未对其赋值。这和其它语言可能有些不一样(特别是编译型语言),它们可能会无视变量赋值以及变量使用的位置先后关系。
若是上面的示例中,函数myfunc调用以前,将变量x赋值为另外一个值:
x=3 def myfunc(a,b): c=10 print(x,a,b,c) x=33 myfunc(5,6)
这时将输出:"33 5 6 10"。由于x是全局变量,只有在函数调用的时候才会去找到变量x对应的值,而这时全局变量的值已是33。
匿名函数是指没有名称的函数,任何编程语言中,匿名函数都扮演着重要角色,它的功能很是灵活,可是匿名函数中的逻辑通常很简单,不然直接使用命名函数更好,匿名函数经常使用于回调函数、闭包等等。
在python中使用lambda关键字声明匿名函数,python中的lambda是一个表达式而不是一个语句,这意味着某些语句环境下可能没法使用def声明函数,但却可使用lambda声明匿名函数。固然,匿名函数能实现的功能,命名函数也以同样都能实现,只不过有时候可能会比较复杂,可读性会更差。
lambda声明匿名函数的方式很简单,lambda关键字后面跟上参数列表,而后一个冒号,冒号后跟一个表达式。
lambda argl, arg2,... argN :expression statement
lambda表达式返回一个匿名函数,这个匿名函数能够赋值给一个变量。
例如:
# 声明匿名函数,并赋值给变量f f = lambda x,y,z: x+y+z print(f)
输出结果:
<function <lambda> at 0x027EA6F0>
既然匿名函数赋值给了变量,这个函数就像是命名变量同样,能够经过这个变量去调用这个匿名函数。固然,它毕竟仍是匿名函数,正如上面输出的结果中function <lambda>
所示。并且,匿名函数并不是必定要赋值给变量。
# 调用匿名函数 print(f(2,3,4)) # 输出9
匿名函数的返回值是冒号后面的表达式计算获得的结果。对于上面的示例,它等价于return x+y+z
。
由于lambda是一个表达式,因此能够写在任何表达式能够出现的位置处,而某些语句上下文环境中,并不能直接使用def来声明。例如,将函数保存到一个列表中:
L=[ lambda x: x * 2, lambda x: x * 3, lambda x: x * 4 ] print(L[0](2)) print(L[1](2)) print(L[2](2))
上面的lambda出如今列表的内部,且这里面的匿名函数并赋值给某个变量。像def语句就没法出如今这样的环境中,若是真要使用def来声明函数,并保存到列表中,只能在L的外部使用def定义,而后将函数名来保存。
def f1(x): return x * 2 def f2(x): return x * 3 def f3(x): return x * 4 L=[f1,f2,f3] print(L[0](2)) print(L[1](2)) print(L[2](2))
看上去没什么问题,但函数定义的位置和列表L定义的位置可能会相差甚远,可读性可能会很是差。
同理的,还能够将匿名函数保存在字典的value位置上:
key='four' print( { 'two':(lambda x: x * 2), 'three':(lambda x: x * 3), 'four':(lambda x: x * 4) }[key](2) )
函数内部能够嵌套函数。通常来讲,在函数嵌套时,内层函数会做为外层函数的返回值(固然,并不是必须)。既然内层函数要做为返回值,这个嵌套的内层函数更可能会是lambda匿名函数。
例如:
def f(x): y=10 def g(z): return x+y+z return g
上面的函数f()中嵌套了一个g(),并返回这个g()。其实上面示例中的g()是一个闭包函数。
既然f()返回的是函数,这个函数能够赋值给其它变量,也能够直接调用:
# 将嵌套的函数赋值给变量myfunc # 这时myfunc()和g()是等价的 myfunc = f(3) print( myfunc(5) ) # 直接调用g() print( f(3)(5) )
固然,嵌套lambda匿名函数也能够,且更常见:
def f(x): y=10 return lambda z: x+y+z
看下面嵌套在循环内部的函数,在每一个迭代过程当中都声明一个匿名函数,这个匿名函数返回循环控制变量i,同时将声明的匿名函数保存到列表L中。
def f(): L=[] for i in range(5): L.append( lambda : i ) return L
但若是调用该函数f(),并调用保存在列表中的每一个匿名函数,会发现它们的值彻底相同,且都是循环迭代的最后一个元素值i=4
。
List = f() print(List[0]()) print(List[1]()) print(List[2]()) print(List[3]()) print(List[4]())
执行结果:
4 4 4 4 4
为何会如此?为何循环迭代过程当中的i没有影响到匿名函数的返回值?这是一个很是值得思考的问题,若是不理解结果,请仔细回顾前文函数变量的细节。若是仍是不理解,请阅读Python做用域详述。
此处给几个示例,这些示例的结果对于只学过python的人来讲,可能会很容易理解,但对于学过其它语言的人来讲,很容易混淆出错。
此处并不会对这些示例的结果进行解释,由于只要理解了前文函数变量的细节,这几个示例的结果很容易理解。
一样,更详细的内容参见Python做用域详述。
以下示例:
x=3 def f(): x=4 g() print("f:",x) def g(): print("g:",x) f()
输出:
g: 3 f: 4
若是在调用函数前,修改全局变量x的值:
x=3 def f(): x=4 g() print("f:",x) def g(): print("g:",x) x=6 f()
输出:
g: 6 f: 4
若是把g()的声明放在f()的内部呢?
x=3 def f(): x=4 def g(): print("g:",x) print("f:",x) x=5 return g f()()
输出:
f: 4 g: 5