深入了解python全局变量,局部变量和命名空间

 更新时间:2021年12月30日 11:42:51   作者:IT娜娜  
这篇文章主要为大家介绍了python全局变量,局部变量和命名空间,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

Python 使用全局和局部变量的方式是特立独行的。虽然在许多或大多数其他编程语言中,如果未另行声明,变量将被视为全局变量,而 Python 则以相反的方式处理变量。如果没有另外声明,它们是本地的。这种方法背后的驱动原因是全局变量通常是不好的做法,应该避免。在大多数情况下,您想使用全局变量,最好使用参数将值放入函数或返回值以将其取出。与许多其他程序结构一样,Python 也通过设计强加了良好的编程习惯。

因此,当您在函数定义中定义变量时,默认情况下它们是该函数的局部变量。也就是说,您对函数体中的此类变量所做的任何操作都不会影响函数外的其他变量,即使它们具有相同的名称。换句话说,函数体是这样一个变量的范围,即这个名称与其值相关联的封闭上下文。

所有变量都有块的作用域,它们在那里被声明和定义。它们只能在声明点之后使用。

简单说一下:变量不必也不能以在 Java 或 C 等编程语言中声明的方式声明。Python 中的变量通过定义它们来隐式声明,即第一次分配值到一个变量,这个变量被声明并自动具有必须分配给它的对象的数据类型。如果您在理解这一点时遇到问题,请参阅我们关于数据类型和变量的章节,请参阅左侧的链接。

函数中的全局和局部变量

在下面的示例中,我们想演示如何在函数体内使用全局值:

def  f ():  
    print ( s )  
s  =  “我爱夏天的巴黎!” 
f ()

输出:

我爱夏天的巴黎!

在调用函数 f() 之前,变量 s 被定义为字符串“我爱夏天的巴黎!”。f() 的主体仅由“print(s)”语句组成。由于没有局部变量 s,即没有赋值给 s,将使用全局变量 s 的值。所以输出将是字符串“我爱夏天的巴黎!”。问题是,如果我们在函数 f() 中改变 s 的值会发生什么?它也会影响全局变量吗?我们在下面的一段代码中对此进行了测试:

def  f ():  
    s  =  "我爱伦敦!" 
    打印( s ) 
s  =  “我爱巴黎!”  
f ()
打印( s )

输出:

我爱伦敦!
我爱巴黎!

如果我们将第一个示例与第二个示例结合起来,即我们首先使用 print() 函数访问 s,希望获得全局值,然后为其分配一个新值呢?给它赋值,意味着 - 正如我们之前所说的 - 创建一个局部变量 s。因此,我们会将 s 作为同一范围内的全局变量和局部变量,即函数体。幸运的是,Python 不允许这种歧义。因此,它会引发错误,正如我们在以下示例中所见:

def  f ():  
   print ( s ) 
   s  =  “我爱伦敦!” 
   打印( s )
s  =  “我爱巴黎!” 
f ()

输出:

UnboundLocalError Traceback (最近一次调用最后一次)
<ipython-input-3-d7a23bc83c27> in <module>
5
6 s = “我爱巴黎!”
----> 7 f ( )
<ipython-input-3-d7a23bc83c27> in f ()
1 def f ( ) :
----> 2 print ( s )
3 s = “我
爱伦敦!” 4 打印( s )
5
UnboundLocalError:赋值前引用了局部变量“s”

变量不能在函数内既是局部的又是全局的。由于在 f() 内部为 s 赋值,因此 Python 决定我们需要一个局部变量,因此在 s 定义之前的第一个打印语句抛出了上面的错误信息。任何在函数内部更改或创建的变量都是局部变量,如果它没有被声明为全局变量。要告诉 Python,我们要使用全局变量,我们必须使用关键字“global”明确说明这一点,如下例所示:

def  f (): 
    global  s 
    print ( s ) 
    s  =  "只在春天,但伦敦也很棒!" 
    打印( s )

s  =  "我在巴黎找课程!"  
f ()
打印( s )

输出:

我正在巴黎寻找课程!
只在春天,但伦敦也很棒!
只在春天,但伦敦也很棒!

函数调用完成后,不能从外部访问函数的局部变量。这是上一个例子的延续:

def  f (): 
    s  =  "我在全球范围内不为人知"
    打印( s ) 
f ()
打印( s )

输出:

我在全球不为人知
只在春天,但伦敦也很棒!

以下示例显示了局部和全局变量以及函数参数的狂野组合:

def  foo ( x ,  y ):
    全局 a 
    a  =  42 
    x , y  =  y , x 
    b  =  33 
    b  =  17 
    c  =  100
    打印( a , b , x , y )
a ,  b ,  x ,  y  =  1 ,  15 ,  3 , 4  
foo ( 17 ,  4 )
打印( a ,  b ,  x ,  y )

输出:

42 17 4 17
42 15 3 4

嵌套函数中的全局变量

如果我们在嵌套函数中使用 global 关键字,我们现在将检查会发生什么。以下示例显示了在各种范围内使用变量“city”的情况:

def  f (): 
    city  =  "Hamburg" 
    def  g (): 
        global  city 
        city  =  "Geneva" 
    print ( "调用前g:"  +  city ) 
    print ( "现在调用g:" ) 
    g () 
    print ( "调用后g: "  + 城市)
f () 
print ( "主城的值:"  +  city )

输出:

之前打电话给g:汉堡
现在调用 g:
打电话后g:汉堡
主要城市价值:日内瓦

我们可以看到嵌套函数 g 中的 global 语句不会影响函数 f 的变量“city”,即它保持其值“Hamburg”。我们还可以从这个例子中推断出,在调用 f() 之后,模块命名空间中存在一个变量 'city',其值为 'Geneva'。这意味着嵌套函数中的 global 关键字不会影响其封闭命名空间的命名空间!这与我们在前一章中发现的一致:在函数内部定义的变量是局部变量,除非它明确标记为全局变量。换句话说,我们可以在任何封闭作用域中引用一个变量名,但我们只能在局部作用域中通过赋值重新绑定变量名,或者通过使用全局声明在模块全局作用域中重新绑定变量名。我们还需要一种方法来访问其他作用域的变量。这样做的方法是非局部定义,我们将在下一章解释。

非局部变量

Python3 引入了非局部变量作为一种新的变量。非局部变量与全局变量有很多共同点。与全局变量的一个区别在于,无法通过使用非局部语句来更改模块范围内的变量,即未在函数内部定义的变量。我们在以下两个示例中展示了这一点:

def  f ():
    全球 城市
    打印( city )
city  =  "法兰克福" 
f ()

输出:

法兰克福

该程序是正确的,并返回“Frankfurt”作为输出。我们将在以下程序中将“全局”更改为“非本地”:

def  f ():
    非本地 城市
    打印( city )
city  =  "法兰克福" 
f ()

输出:

文件“<ipython-input-9-97bb311dfb80>” ,第2
行 非本地城市
^
语法错误:未找到非本地“城市”的绑定

这表明非局部绑定只能在嵌套函数内部使用。必须在封闭的函数作用域中定义非局部变量。如果变量未在封闭函数作用域中定义,则变量不能在嵌套作用域中定义。这是与“全局”语义的另一个区别。

def  f (): 
    city  =  "Munich" 
    def  g (): 
        nonlocal  city 
        city  =  "Zurich" 
    print ( "调用前g:"  +  city ) 
    print ( "现在调用g:" ) 
    g () 
    print ( "调用后g: "  + 城市)
city  =  "Stuttgart" 
f () 
print ( "'city' in main:"  +  city )

输出:

打电话之前 g: 慕尼黑
现在调用 g:
拨打 g 后:苏黎世
主要的“城市”:斯图加特

在前面的例子中,变量 'city' 是在调用 g 之前定义的。如果没有定义,我们会得到一个错误:

高清 ˚F ():
    #city = “慕尼黑”
    高清 g ^ ():
        外地 市
        城市 =  “苏黎世”
    打印(“呼叫摹前:”  + 城市)
    打印(“立即致电G:” )
    g ^ ()
    打印(“后呼叫 g: "  +  city )
city  =  "Stuttgart" 
f () 
print ( "'city' in main:"  +  city )

输出:

文件“<ipython-input-11-5417be93b6a6>” ,第4
行 非本地城市
^
语法错误:未找到非本地“城市”的绑定

该程序运行良好 - 如果我们将“非本地”更改为“全局”,在 f - 内有或没有 'city = "Munich"' 行:

def  f (): 
    #city = "Munich" 
    def  g (): 
        global  city 
        city  =  "Zurich" 
    print ( "Before call g:"  +  city ) 
    print ( "Calling g now:" ) 
    g () 
    print ( "After 调用g:" )呼叫 g: " +  city )
city  =  "Stuttgart" 
f () 
print ( "'city' in main:"  +  city )

输出:

打电话之前:斯图加特
现在调用 g:
拨打 g 后:苏黎世
主要的“城市”:苏黎世

然而有一个巨大的不同:全局 x 的值现在发生了变化!

相关文章

  • 详解Python中的函数参数传递方法*args与**kwargs

    详解Python中的函数参数传递方法*args与**kwargs

    本文将讨论Python的函数参数。我们将了解args和kwargs,/和的都是什么,虽然这个问题是一个基本的python问题,但是在我们写代码时会经常遇到,比如timm中就大量使用了这样的参数传递方式
    2023-03-03
  • django执行数据库查询之后实现返回的结果集转json

    django执行数据库查询之后实现返回的结果集转json

    这篇文章主要介绍了django执行数据库查询之后实现返回的结果集转json,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-03-03
  • python协程库asyncio(异步io)问题

    python协程库asyncio(异步io)问题

    这篇文章主要介绍了python协程库asyncio(异步io)问题,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-11-11
  • Django框架中的对象列表视图使用示例

    Django框架中的对象列表视图使用示例

    这篇文章主要介绍了Django框架中的对象列表视图使用示例,Django是重多Python人气web框架中最为著名的一个,需要的朋友可以参考下
    2015-07-07
  • Python中的shape[0]、shape[1]和shape[-1]使用方法

    Python中的shape[0]、shape[1]和shape[-1]使用方法

    shape函数是Numpy中的函数,它的功能是读取矩阵的长度,比如shape[0]就是读取矩阵第一维度的长度,这篇文章主要介绍了Python中的shape[0]、shape[1]和shape[-1]使用方法,需要的朋友可以参考下
    2023-07-07
  • python实现canny边缘检测

    python实现canny边缘检测

    本文主要讲解了canny边缘检测原理:计算梯度幅值和方向、根据角度对幅值进行非极大值抑制、用双阈值算法检测和连接边缘以及python 实现
    2020-09-09
  • Ubuntu 14.04+Django 1.7.1+Nginx+uwsgi部署教程

    Ubuntu 14.04+Django 1.7.1+Nginx+uwsgi部署教程

    django+uwsgi的部署实在是太蛋疼了.网上已有的教程似乎有新版本的兼容问题。最后跑到uwsgi官网上找的教程终于跑通了.. 不过官网的教程似乎有引导教学性质,部署的时候就显得很绕弯路,在这里记录下来精简内容
    2014-11-11
  • Python中识别图片/滑块验证码准确率极高的ddddocr库详解

    Python中识别图片/滑块验证码准确率极高的ddddocr库详解

    验证码的种类有很多,它是常用的一种反爬手段,包括:图片验证码,滑块验证码,等一些常见的验证码场景。这里推荐一个简单实用的识别验证码的库 ddddocr (带带弟弟ocr)库,希望大家喜欢
    2023-02-02
  • Python生成随机数组的方法小结

    Python生成随机数组的方法小结

    这篇文章主要介绍了Python生成随机数组的方法,结合实例形式总结分析了Python使用random模块生成随机数与数组操作相关技巧,需要的朋友可以参考下
    2017-04-04
  • 实例解析Python设计模式编程之桥接模式的运用

    实例解析Python设计模式编程之桥接模式的运用

    这篇文章主要介绍了Python设计模式编程之桥接模式的运用,桥接模式主张把抽象部分与它的实现部分分离,需要的朋友可以参考下
    2016-03-03

最新评论