zoukankan      html  css  js  c++  java
  • 作用域(全局变量和局部变量)

    变量到底是什么呢?可将其视为指向值的名称。因此,执行赋值语句x = 1后,名称x指向值1。这几乎与使用字典时一样(字典中的键指向值),只是你使用的是“看不见”的字典。实际上,这种解释已经离真相不远。有一个名为vars的内置函数,它返回这个不可见的字典:

    >>> x = 1
    >>> scope = vars()
    >>> scope['x']
    1
    >>> scope['x'] += 1
    >>> x
    2

    警告 一般而言,不应修改vars返回的字典,因为根据Python官方文档的说法,这样做的结果是不确定的。换而言之,可能得不到你想要的结果。

    这种“看不见的字典”称为命名空间作用域。那么有多少个命名空间呢?除全局作用域外,每个函数调用都将创建一个。

    >>> def foo(): x = 42
    ...
    >>> x = 1
    >>> foo()
    >>> x
    1

    在这里,函数foo修改(重新关联)了变量x,但当你最终查看时,它根本没变。这是因为调用foo时创建了一个的命名空间,供foo中的代码块使用。赋值语句x = 42是在这个内部作用域(局部命名空间)中执行的,不影响外部(全局)作用域内的x。在函数内使用的变量称为局部变量(与之相对的是全局变量)。参数类似于局部变量,因此参数与全局变量同名不会有任何问题。

    >>> def output(x): print(x)
    ...
    >>> x = 1
    >>> y = 2
    >>> output(y)
    2

    到目前为止一切顺利。但如果要在函数中访问全局变量呢?如果只是想读取这种变量的值(不重新关联它),通常不会有任何问题。

    >>> def combine(parameter): print(parameter + external)
    ...
    >>> external = 'berry'
    >>> combine('Shrub')
    Shrubberry

    警告 像这样访问全局变量是众多bug的根源。务必慎用全局变量。

    “遮盖”的问题

    读取全局变量的值通常不会有问题,但还是存在出现问题的可能性。如果有一个局部变量或参数与你要访问的全局变量同名,就无法直接访问全局变量,因为它被局部变量遮住了。

    如果需要,可使用函数globals来访问全局变量。这个函数类似于vars,返回一个包含全局变量的字典。(locals返回一个包含局部变量的字典。)

    例如,在前面的示例中,如果有一个名为parameter的全局变量,就无法在函数combine中访问它,因为有一个与之同名的参数。然而,必要时可使用globals()['parameter']来访问它。

    >>> def combine(parameter):
    ...     print(parameter + globals()['parameter'])
    ...
    >>> parameter = 'berry'
    >>> combine('Shrub')
    Shrubberry

    重新关联全局变量(使其指向新值)是另一码事。在函数内部给变量赋值时,该变量默认为局部变量,除非你明确地告诉Python它是全局变量。那么如何将这一点告知Python呢?

    >>> x = 1
    >>> def change_global():
    ...     global x
    ...     x = x + 1
    ...
    >>> change_global()
    >>> x
    2

     作用域嵌套

    Python函数可以嵌套,即可将一个函数放在另一个函数内,如下所示:

    def foo():
        def bar():
            print("Hello, world!")
        bar()

    嵌套通常用处不大,但有一个很突出的用途:使用一个函数来创建另一个函数。这意味着可像下面这样编写函数:

    def multiplier(factor):
        def multiplyByFactor(number):
            return number * factor
        return multiplyByFactor

    在这里,一个函数位于另一个函数中,且外面的函数返回里面的函数。也就是返回一个函数,而不是调用它。重要的是,返回的函数能够访问其定义所在的作用域。换而言之,它携带着自己所在的环境(和相关的局部变量)!

    每当外部函数被调用时,都将重新定义内部的函数,而变量factor的值也可能不同。由于Python的嵌套作用域,可在内部函数中访问这个来自外部局部作用域(multiplier)的变量,如下所示:

    作用域嵌套函数的调用方式:

    def multiplier(factor):
        def multiplyByFactor(number):
            return number * factor
        return multiplyByFactor
    
    >>> double = multiplier(2)
    >>> double(5)
    10
    >>> triple = multiplier(3)
    >>> triple(3)
    9
    >>> multiplier(5)(4)
    20

    multiplyByFactor这样存储其所在作用域的函数称为闭包

    通常,不能给外部作用域内的变量赋值,但如果一定要这样做,可使用关键字nonlocal。这个关键字的用法与global很像,让你能够给外部作用域(非全局作用域)内的变量赋值。

    global和nonlocal区别:

    第一,两者的功能不同。global关键字修饰变量后标识该变量是全局变量,对该变量进行修改就是修改全局变量,而nonlocal关键字修饰变量后标识该变量是上一级函数中的局部变量,如果上一级函数中不存在该局部变量,nonlocal位置会发生错误(最上层的函数使用nonlocal修饰变量必定会报错)。

    第二,两者使用的范围不同。global关键字可以用在任何地方,包括最上层函数中和嵌套函数中,即使之前未定义该变量,global修饰后也可以直接使用,而nonlocal关键字只能用于嵌套函数中,并且外层函数中定义了相应的局部变量,否则会发生错误(见第一)。
    详细说明地址:https://blog.csdn.net/xcyansun/article/details/79672634

    函数id()的用法:

    功能:返回变量地址

    也就是is对比为真的根源,地址相同则相同为真,而相等并不一定相同。

  • 相关阅读:
    faster rcnn学习(三)
    too many values to unpack (expected 2)
    RuntimeWarning: overflow encountered in ubyte_scalars
    C#中excel读取和写入
    C#中使用Sql对Excel条件查询
    IIS上部署MVC网站,打开后ExtensionlessUrlHandler-Integrated-4.0解决方法IIS上部署MVC网站,打开后500错误
    C#微信公众平台账号开发,从零到整,步骤详细。
    VS快捷键大全
    ASP.NET将文件写到另一服务器
    开放api接口签名验证
  • 原文地址:https://www.cnblogs.com/iBoundary/p/11242438.html
Copyright © 2011-2022 走看看