标签:编写 res src 定义 共享 传值 变量 查找 数通
函数是把一些语句集合在一起的程序结构,用于把复杂的流程细分成不同的组件,能够减少代码的冗余、代码的复用和修改代码的代价。
函数可以0个、1个或多个参数,向函数传递参数,可以控制函数的流程。函数还可以返回代码执行的结果,从技术上讲,任何函数都要返回结果,一个没有返回值的函数会自动返回none对象。如果调用者需要函数返回结果,需要显式使用return语句。
Python使用def 语句将创建一个函数对象,并将其赋值给一个变量名,()内是函数的参数,参数通过赋值向参数传值。
def fun_name (arg1,age2...): fun_body
return语句表示函数调用的结束,并把结果传递给调用者。return语句是可选的,如果它没有出现,那么函数将会在控制流执行完函数主体时结束。
1,def是可执行的语句
def语句是实时执行的,不仅def语句,Python中的所有语句都是实时运行的,并没有独立的编译时间。def语句是一个可执行的语句,在def执行前,函数并不存在,直到def语句执行之后,函数才被创建。
2,函数是一个对象,函数名是变量
def语句是一个赋值语句,函数是一个对象,函数名是一个变量,def语句设置函数名和函数对象的引用。
当def语句运行的时候,它创建了一个新的函数对象,并将其赋值给一个变量名。
3,参数是通过赋值传递的
Python通过赋值(=)把参数传递给函数,这和普通的赋值语句(a=1,或a=b)的行为是相同。当传递常量给参数时,参数引用的是一个全新的对象;当传递变量给参数,参数和变量是对象的共享引用。
4,函数是可以嵌套的
一个def是一个语句,可以出现在任一语句可以出现的地方,甚至嵌套在其他的语句中。这就是说,函数内部可以嵌套函数的定义,例如:
def times(x,y): z=x*y def print_result(): print(z) print_result()
函数 print_result()是一个嵌入函数,定义在函数times(x,y)之内。
实际上,Python的函数是有层次结构,最外层的def是顶层函数,在顶层函数内部定义的函数是嵌套函数。
函数通过表达式调用,传入一些值,并返回结果。函数调用的格式是:函数名 + (args),小括号中是传递给参数的变量或值,例如:
func_name(var1,var2...)
如果函数存在返回值,使用变量来接收函数的返回值:
ret_value=fun_name(var1,var2...)
在调用函数时,函数的行为依赖于类型,这是因为函数是语句的集合,语句包含操作符,而操作符的行为是依赖于类型的,
例如,函数times返回两个参数的乘积,当传入数字时,函数 times(2,4) 返回8,* 的作用是计算乘积;当传入字符类型时,函数 times(‘ab‘,2) 返回‘abab‘,*号的作用是重复字符串。换句话说,函数times()的作用取决于传递给它的值。
def times(x,y): return x *y
调用函数时,这种依赖于类型的行为称为多态,就是说,一个操作的作用取决于操作对象的类型。函数的多态性,使得函数可以自动适用于所有类别的对象类型。
如果传给函数的对象有预期的方法和表达式操作符,那么函数就兼容对象。如果传递的对象不支持预期的接口,Python会在 * 表达式运行时检测到错误,并自动抛出一个异常。
这种特性,使得Python代码不应该关心特定的类型,函数应该为对象编写接口,而不是数据类型。当然,这种多态的编程模型意味着:必须测试代码去检测执行结果是否错误,而不是编写代码进行类型检查。
在Python代码中变量无处不在,命名空间就是保存变量名的地方,变量名能够访问(可见)的命名空间叫做作用域。
当在程序中使用变量名时,Python创建、改变或者查找变量都是在命名空间中进行的,变量名被赋值的位置决定了变量名能够被访问的范围。
1,变量的分类
Python中的变量在第一次被赋值时创建,并且必须经过赋值后才能使用。由于没有变量的声明,Python把变量名被赋值的地点关联为(绑定为)一个特定的命名空间。
根据变量的命名空间,把变量大致分为三类:
2,变量的作用域
变量的作用域是指变量可见的范围,一个变量的作用域总是由变量被赋值的地方决定的,也就是说,变量被赋值的地方决定了变量可见的范围。
在默认情况下,一个函数的所有变量名都是与函数的命名空间相关联的:
由于变量可以在三个地方分配,那么变量的作用域实际上分为三类:
3,作用域法则
所有变量名都可以归纳为内置的(builtin)、全局的(global)和本地的(local)。
内置的模块是Python预先定义好,可以直接引用的。
模块定义的是全局作用域,全局作用域的作用范围仅限于单个模块(文件),也就是说,在一个文件的顶层的变量名对于这个文件内部的代码而言是全局的。
在默认情况下,在函数内部,赋值的变量名除非声明为全局变量或非本地变量之外,都是本地作用域内的。函数还定义了嵌套的作用域,使其内部使用的变量名本地化,以便函数内部使用的变量名不会与函数外的变量名冲突。每次对函数的调用都会创建一个新的本地作用域。如果需要给一个嵌套的def中的变量名赋值,从Python 3.0开始,可以使用 nonlocal语句声明来做到。
注意:模块顶层的函数名是全局变量,函数内部的def定义的是局部变量;函数的参数是本地变量;一个函数内部的任何类型的赋值都会把一个变量划定为本地的,这意味着,函数内部的赋值(=)语句,def语句等,定义的都是本地变量。
4,变量名解析(LEGB原则)
变量名的解析遵从LEGB原则,当引用一个变量时,Python按照以下顺序依次进行查找:从本地变量中、在任意上层函数的作用域、在全局作用域,最后在内置作用域中查找。
LEGB法则解析变量名的详细机制:
把嵌套作用域定义为:在当前的def语句之外,在顶层def语句之内的作用域,嵌套作用域的解析细节:
5,在函数内引用全局变量
global不是声明一个类型,而是声明命名的命名空间是全局的,也就是说,告诉函数打算声明一个或多个全局变量名。
对于全局变量名,这里对用法作一个总结:
例如,x是全局变量,在函数func中使用global 声明x是全局变量,对x赋值,就是修改全局变量的值:
x=11 def func(): global x x=12
使用global语句把变量声明为全局变量,这样,在函数内部就可以修改全局变量的值,也就是说,global语句允许在def中修改全局变量的值。
global语句包含了关键字global,其后跟着一个或多个由逗号分开的变量名,当在函数内被赋值或引用时,所有列出来的变量都被映射到全局变量名。
global x,y,z
6,在函数内引用上层的非本地变量
Pytho 3.0 引入了nonlocal语句,用于在一个函数内声明一个非本地的变量,该变量定义于一个def语句中,并且位于嵌套作用域的上层。
例如,函数foo1定义了变量var1和var2,要想在函数foo2中改变它们的值,必须在foo2中使用nonlocal语句把它们声明为非本地变量:
def foo1: var1=1 var2=2 ... def foo2: nonlocal var1,var2,..
nonlocal语句是一个声明语句,用于把函数内的变量声明为非本地变量。非本地变量是指不在本函数内定义的,而是在上层函数中定义的本地变量。
nonlocal语句的用法解析:
nonlocal语句提供了一种方式,使得嵌套的函数能够提供可写的状态信息,以便在随后调用嵌套的函数时,能够记住这些信息。简而言之,nonlocal语句的引入使得Python允许修改非本地变量。
Python的闭合函数是指一个能够记住嵌套作用域的变量值的函数,尽管那个作用域已经不存在了。
例如,创建一个闭合函数maker,该函数生成并返回一个嵌套函数action,却并调用这个内嵌的函数。
def maker(x): def action(y): return x*y return action
调用闭合函数,得到的是生成的内嵌函数的一个引用。当我们调用闭合函数,它会返回内嵌函数的引用;当调用内嵌函数action时,我们发现尽管闭合函数已经返回并退出,但是,内嵌函数记住了闭合函数内部的变量x的值。
f=maker(2)
f(3)
也就是说,闭合函数的本地作用域的信息被保留了下来。为了能够在内嵌的def中使用变量x的值,Python自动记住了所需要的上层作用域的任意值。
注意:如果lambda或者def在函数中定义,嵌套在一个循环之中,并且嵌套的函数引用了一个上层作用域的变量,该变量被循环所改变,所有在这个循环中产生的函数将会由相同的值——在最后一次循环中完成时被引用变量的值。
>>> def maker(): ... acts=[] ... for i in range(5): ... acts.append(lambda x:i**x) ... return acts ... >>> acts=maker() >>> acts[0](2) 16
因为嵌套作用域中的变量在嵌套的函数被调用时才进行检查,所以,它们实际上记住的是同样的值(在最后一次循环迭代中循环变量的值)。
也就是说,只有当调用acts[0](2)时,采取检查变量i的值,此时变i的值是最后一次迭代的值4。要解决这类问题,必须在函数maker调用时,对i的值进行评估,并保存起来。
>>> def maker(): ... acts=[] ... for i in range(5): ... acts.append(lambda x, i=i : i**x) ... return acts
为了让这类代码能够工作,必须使用默认参数把当前的值传递给嵌套作用域的变量。因为默认参数是在嵌套函数创建时评估的(而不是其稍后调用时),所以,每一个函数都记住了自己的变量 i 的值。
参考文档:
Python 语言学习 第七篇:函数1(定义、调用和变量的作用域)
标签:编写 res src 定义 共享 传值 变量 查找 数通
原文地址:https://www.cnblogs.com/ljhdo/p/10104834.html