美文网首页
第十七章、作用域

第十七章、作用域

作者: 聽風踏雪 | 来源:发表于2017-06-07 02:38 被阅读0次

    Python作用域基础

    当你在一个程序中适用变量名时,Python创建、改变或查找变量名都是在所谓的命名空间(一个保存变量名的地方)中进行的。当我们谈论到搜索变量名对应于代码的值的时候,作用域这个术语指的就是命名空间。

    关于所有变量名,包括作用域的定义在内,都是Python赋值的时候生成的。

    在默认的情况下,一个函数的所有变量名都是与函数的命名空间相关联的。这意味着:

    ①、一个在def内定义的变量名能够被def内的代码使用。不能在函数的外部引用这样的变量名。

    ②、def之中的变量名与def之外的变量名并不冲突,即使是使用在别处的相同的变量名。

    变量可以在3个不同的地方分配,分别对应3个不同的作用域:

    ①、如果一个变量在def内赋值,它被定位在这个函数之内。

    ②、如果一个变量在一个嵌套的def中赋值,对于嵌套的函数来说,它是非本地的。

    ③、如果在def之外赋值,它就是整个文件全局的。

    1、作用域法则:

    ①、内嵌的模块是全局作用域。

    ②、全局作用域的作用范围仅限于单个文件。

    ③、每次对函数的调用都创建了一个新的本地作用域。

    ④、赋值的变量名除非声明为全局变量或非本地变量,否则均为本地变量。

    ⑤、所有其他的变量名都可以归纳为本地、全局或者内置的。

    2、变量名解析:LEGB原则:

    对于一个def语句:

    ①、变量名引用分为三个作用域进行查找:首先是本地,之后是函数内(如果有的话),之后是全局,最后是内置。

    ②、在默认情况下,变量名赋值会创建或者改变本地变量。

    ③、全局声明和非本地声明将赋值的变量名映射到模块文件内部的作用域。

    Python的变量名解析机制有时称为LEGB法则,这也是由作用域的命令而来的。

    ①、当在函数中使用未认证的变量名时,Python搜索4个作用域【本地作用域(L),之后是上一层结构中def或者lambda的本地作用域(E),之后是全局作用域(G)),最后是内置作用域(B)】并且在第一处能够找到这个变量名的地方停下来。如果变量名在这次搜索中没有找到,Python会报错。

    ②、当在函数中给一个变量名赋值时(而不是在一个表达式中对其进行引用),Python总是创建或改变本地作用域的变量名,除非它已经在那个函数中声明为全局变量。

    ③、当在函数之外给一个变量名赋值时(也就是,在一个模块文件的顶层,或者是在交互提示模式下),本地作用域与全局作用域(这个模块的命名空间)是相同的。

    3、作用域实例:

    4、内置作用域:

    5、global语句:

    ①、全局变量是位于模块文件内部的顶层的变量名。

    ②、全局变量如果是再函数内被赋值的话,必须经过声明。

    ③、全局变量名在函数的内部不经过声明也可以被引用。

    6、最小化全局变量:

    7、最小化文件间的修改:

    8、其他访问全局变量的方法:

    作用域和嵌套函数

    1、嵌套作用域的细节:

    对于一个函数:

    ①、一个引用(X)首先在本地(函数内)作用域查找变量名X;之后会在代码的语法上嵌套了的函数中的本地作用域,从内到外查找;之后查找当前的全局作用域(模块文件);最后再内置作用域内(模块__builtin__)。全局声明将会直接从全局(模块文件)作用域进行搜索。

    ②、在默认情况下,一个赋值(X=value)创建或改变了变量名X的当前作用域。

    2、嵌套作用域举例:

    ①、工厂函数:

    根据要求的对象,这种行为有时也叫做闭合(closure)或者工厂函数——一个能够记住嵌套作用域的变量值的函数,尽管那个作用域或许已经不存在了。

    ②、使用默认参数来保留嵌套作用域的状态:

    ③、嵌套作用域和lambda:

    像def一样,lambda表达式引入了新的本地作用域。

    ④、作用域与带有循环变量的默认参数相比较:

    在已给出的法则中有个值得注意的特例:如果lambda或者def在函数中定义,嵌套在一个循环之中,并且嵌套的函数引用了一个上层作用域的变量,该变量被循环所改变,所有在这个循环中产生的函数将会有相同的值——在最后一次完成时被引用变量的值。

    ⑤、任意作用域的嵌套:

    nonlocal语句

    1、nonlocal基础:

    ①、global使得作用域查找从嵌套的模块的作用域开始,并且允许对那里的名称赋值。如果名称不存在于该模块,作用域查找继续到内置作用域,但是,对全局名称的赋值总是在模块的作用域中创建或修改它们。

    ②、nonlocal限制作用域查找知识嵌套的def,要求名称已经存在于那里,并且允许对它们赋值。作用域查找不会继续到全局或内置作用域。

    2、nonlocal应用:

    ①、使用nonlocal进行修改:

    ②、边界情况:

    首先,和global语句不通,当执行一条nonlocal语句时,nonlocal名称必须已经在一个嵌套的def作用域中赋值过,否则将会得到一个错误——不能通过在嵌套的作用域中赋给它们一个新值来创建它们。

    其次,nonlocal限制作用域查找仅为嵌套的def,nonlocal不会在嵌套的模块的全局作用域或所有def之外的内置作用域中查找,即便已经有了这些作用域。

    3、为什么使用nonlocal:

    ①、与全局共享状态:

    在Python2.6中实现nonlocal效果的一种通用方法也是较早的方法,就是直接把状态移出全局作用域(嵌套的模块)。

    ②、使用类的状态(预览):

    Python2.6中针对可改变信息的另一种较早的方法是使用带有属性的类,从而让状态信息的访问比隐式的范围查找规则更明确。

    ③、使用函数属性的状态:

    我们有时候可以使用函数属性实现与nonlocal相同的效果——用户定义的名称直接附加给函数。

    本章小结

    这一章,我们学习了关于函数的两个关键概念:作用域(当使用时变量如何查找)。正如我们所学的那样,变量作为它所赋值的函数定义的本地变量,除非它们特定地声明为全局变量或非本地变量。我们也学过了一些更高级的作用域概念,包括嵌套函数作用域和函数属性。最后,我们学习了一些通用的设计观点(避免使用全局变量和跨文件间的修改)。

    相关文章

      网友评论

          本文标题:第十七章、作用域

          本文链接:https://www.haomeiwen.com/subject/dfzbfxtx.html