首页 > 编程语言 >【python基础之命名空间与作用域】---命名空间与作用域

【python基础之命名空间与作用域】---命名空间与作用域

时间:2023-12-11 18:57:19浏览次数:45  
标签:fun1 函数 作用域 print python 命名 全局变量 变量

title:  【python基础之命名空间与作用域】---命名空间与作用域
date:  2023-12-11  18:44:060
updated: 2023-12-11 18:44:00
description: 
cover: 
       https://home.cnblogs.com/u/dream-ze/

image

【一】名称空间与闭包

【1】什么是名称空间

  • 名称空间即存放名字与对象映射/绑定关系的地方。
    • 对于x=3
    • Python会申请内存空间存放对象3,然后将名字x与3的绑定关系存放于名称空间中
    • del x表示清除该绑定关系。
  • 在程序执行期间最多会存在三种名称空间
内置名称(build-in names):python语音内置的名称,比如函数名(abs,char)和异常名称(BaseException、Exception)等等。
全局变量(global names):模块中定义的名称,记录了模块的变量,包括函数、类、其他导入的模块,模块级的变量和常量
局部名称(local names): 函数中定义的名称,记录了函数的变量,包括函数的参数和局部定义的变量(类中定义的也是)

image

【2】内建名称空间

  • 伴随python解释器的启动/关闭而产生/回收
    • 因而是第一个被加载的名称空间,用来存放一些内置的名字,比如内建函数名
print(max)
# <built-in function max>

【3】全局名称空间

  • 伴随python文件的开始执行/执行完毕而产生/回收,是第二个被加载的名称空间,文件执行过程中产生的名字都会存放于该名称空间中,如下名字
import sys #模块名sys

x=1 #变量名x

if x == 1:
    y=2 #变量名y

def foo(x): #函数名foo
    y=1
    def bar():
        pass

Class Bar: #类名Bar
	pass

【4】局部名称空间

  • 伴随函数的调用/结束而临时产生/回收,函数的形参、函数内定义的名字都会被存放于该名称空间中
def foo(x):
    y=3 #调用函数时,才会执行函数代码,名字x和y都存放于该函数的局部名称空间中

【5】名称空间的加载顺序是

  • 内置名称空间->全局名称空间->局部名称空间,
  • 而查找一个名字,必须从三个名称空间之一找到,查找顺序为:
  • 局部名称空间->全局名称空间->内置名称空间。

【二】作用域

作用域是一个python程序可以直接访问命名空间的正文区域
在python程序中,如果直接访问一个变量,会从内到外的作用域去查找,找不到就会报错,变量未定义。
变量的访问权限取决于变量在哪赋值
变量的作用域决定了在哪一部分程序可以访问哪个特定的变量名称

【1】变量作用域

  • 变量的作用域
    • Python是静态作用域,也就是说Python中,变量的作用域源于它在代码中的位置
    • 在不同的位置,可能有不同的命名空间。命名空间是变量作用域的体现形式
  • python变量作用域一般有4种:
- Local(局部变量)			L:最内层,包含局部变量,比如一个函数/方法内部。
- Enclosed(嵌套)		 E: 包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套											函数,一个函数(或类)A里又包含了一个函数B,那么对于B中的名称来说A中的作用												域就叫做nonlocal
- Global(全局)      G: 当前脚步的最外层,比如当前模块的全局变量
- Built-in(内置)    B:包含了内建的变量/关键字等,最后被搜索出来


(1)Local(局部变量)

  • Local(局部变量):暂时的存在,依赖于创建该局部作用域的函数。函数存,则局部变量存,函数亡,则局部变量亡。

  • 作用范围:当前整个函数体范围

    # 定义一个函数,函数内部就是局部作用域
    def fun():
        # 只有在函数内部的变量
        b = 2
        print(b)  # 输出2
    
    
    fun()
    # 调用函数后,发现找不到变量 b 是因为在全局作用域中找不到 变量 b
    print(b)  # 报错
    
    '''
    Traceback (most recent call last):
      File "E:\PythonProjects\def_func.py", line 16, in <module>
        print(b)  # 报错
    NameError: name 'b' is not defined
    '''
    

image

(2)Enclosed(嵌套)

  • Enclosed(嵌套):一般是在函数中嵌套函数的时候,外层函数的变量作用域。

  • 作用范围:闭包函数

    # Enclosed(嵌套)作用域
    def fun1():
        b = 2
        print("这是fun1打印的:", b)
    
        def fun2():
            # 函数 func1 里面 嵌套的 函数 func2 里面的作用域就是 嵌套作用域
            print("这是fun2打印的:", b)
        
        # 将内部函数 func2 的内存地址返回
        return fun2
    
    
    # 调用 函数 fun1 , 函数 func1 的返回值是内部函数 fuc2的函数地址
    temp = fun1()
    
    # 调用 函数 fun1 的返回值(fuc2的函数地址) , 从而执行 函数 fuc2
    temp()
    # 这是fun1打印的: 2
    # 这是fun2打印的: 2
    
    • 在这里函数fun2里面并没有定义变量b,但是它能够引用外层函数fun1定义的b变量,此时变量b的作用域就是Enclosed

image

(3)Global(全局)

  • Global(全局):一般模块文件顶层声明的变量具有全局作用域,从外部来看,模
    块的全局变量就是一个模块对象的属性,仅限于单个模块文件中。
  • 作用范围:当前模块(文件)
# Global(全局)作用域

# 定义在全局的变量,在本文件任意位置可调用该变量
a = 2


def fun1():
    print("这是fun1打印的:", a)


fun1()
print(a)

# 这是fun1打印的: 2
# 2

image

(4)Built-in(内置)

  • Built-in(内置):解释器内置的变量,比如int, str等。

  • 作用范围:所有模块(文件)

  • Python中没有块级作用域。

  • 块级作用域:代码块中的变量,比如if、while、for后面的代码

【2】LEGB规则

  • LGEB规则:按照L--->E--->G--->B的顺序查找变量。
    • 也就是,当不同命名空间具有相同变量名称的变量时,我们首先查找局部变量,如果没有查到,再向全局变量查找。

(1)基于命名空间的常见变量类型

  • 局部变量:
    • 在一个函数体的内部定义的变量
    • 作用域为函数内部
    • 查看局部变量命令:locals()
  • 全局变量
    • 在函数体外部,文件最外层定义的变量
    • 作用域为整个文件内部
    • 查看全局变量命令:globals()
  • 注意:
    • 变量访问规则:从内到外
    • 全局变量和局部变量重名时,采用就近原则

(2)案例讲解

# 定义了一个全局变量G,并把"G全局"赋值给a
a = "G全局"


def myfunc():
    # 定义了一个局部变量a,并把"E局部1"赋值给a
    a = "E局部"

    def inner():
        # 定义了一个局部变量a,并把"L局部2"赋值给a
        a = "L局部2"
        print(f"inner打印的a:{a}")

    inner()
    print(f"myfunc打印的a:{a}")


myfunc()
print(f"__main__打印的a:{a}")
# inner打印的a:L局部2
# myfunc打印的a:E局部
# __main__打印的a:G全局
  • 结果如下
    image

  • 代码结果分析流程
    image

(3)变量的使用规则

  • 创建变量时从上往下创建,搜索变量时从下往上搜索。
  • 创建变量时,下层变量会覆盖上层同名变量,但不会改变上层变量的值,除非使用gloable和nonlocal关键字声明

image

【3】变量的修改

(1)global修改全局变量

  • 一般全局变量一经定义后几乎是不用改的,也不允许在局部修改全局变量,除非使用Global关键字声明。

    # 定义一个全局变量 a
    a = 1
    
    
    def fun1():
        # 修改全局变量
        a = a + 2
        print(a)
    
    
    fun1()
    print(a)
    '''
    Traceback (most recent call last):
      File "/Users/xxx/Downloads/笔记/pythonProject/py-days-test/test.py", line 11, in <module>
        fun1()
      File "/Users/xxx/Downloads/笔记/pythonProject/py-days-test/test.py", line 7, in fun1
        a = a + 2
    UnboundLocalError: local variable 'a' referenced before assignment
    '''
    

image

  • 可以看到,当我们试图在函数fun1创建的局部作用域内改变全局变量a就会报错

    • 但如果在修改之前使用global关键字声明时,就会正常修改外部的全局变量a

      # 定义一个全局变量 a
      a = 1
      
      
      def fun1():
          global a
      
          # 修改全局变量
          a = a + 2
          print(f"函数内部修改全局变量 :>>>> {a}")
      
      
      fun1()
      print(f"调用函数后全局变量 :>>>> {a}")
      # 函数内部修改全局变量 :>>>> 3
      # 调用函数后全局变量 :>>>> 3
      

image

(2)nonlocal修改外层函数变量

  • 在函数中嵌套函数时,嵌套在里面的函数创建的作用域内一般也是不允许改变外层函数变量的值的

  • 除非是nonlocal关键字声明

  • 如下

    # 不使用nonocal声明,修改外层函数变量值
    def fun1():
        a = 1
    
        def fun2():
            a += 2
            print(a)
    
        return fun2
    
    
    temp = fun1()  # 调用fun1
    temp()  # 调用fun2
    '''
    Traceback (most recent call last):
      File "/Users/xxx/Downloads/笔记/pythonProject/py-days-test/test.py", line 13, in <module>
        temp()  # 调用fun2
      File "/Users/xxx/Downloads/笔记/pythonProject/py-days-test/test.py", line 6, in fun2
        a += 2
    UnboundLocalError: local variable 'a' referenced before assignment
    '''
    

image

可以看到,报错和在函数内不使用global修改全局变量报的错是一样的

  • 当使用nonlocal声明后再修改就不会报错了

    # 不使用nonocal声明,修改外层函数变量值
    def fun1():
        a = 1
        print(f"我是func1的变量修改前:{a}")
    
        def fun2():
            nonlocal a  # 使用nonocal声明
            a += 2
            print(f"这是内层嵌套修改局部变量后 :>>>> {a}")  # 修改后
    
        print(f"我是func1的变量修改后:{a}")
        return fun2
    
    
    temp = fun1()  # 调用fun1
    temp()  # 调用fun2
    
    # 我是func1的变量修改前:1
    # 我是func1的变量修改后:1
    # 这是内层嵌套修改局部变量后 :>>>> 3
    

image
可以看到是正常修改的

标签:fun1,函数,作用域,print,python,命名,全局变量,变量
From: https://www.cnblogs.com/queryH/p/17895130.html

相关文章

  • ubuntu 下 docker 中部署 jenkins,并配置安卓 python 开发环境
    1、ubuntu中下载AndroidSdk#安装unzip工具sudoaptupdatesudoaptinstallunzip#下载AndroidSDKwgethttps://dl.google.com/android/repository/commandlinetools-linux-7302050_latest.zip#解压unzipcommandlinetools-linux-7302050_latest.zip-dandroid......
  • Python编译升级3.7.x
    CentOS7自带的Python为3.6.x,但因项目需要,要升级到3.7.x,记录遇到的一些问题。Python3.7.x需要先升级OpenSSL到1.1.x后的版本,否则会报下面的错误WARNING:pipisconfiguredwithlocationsthatrequireTLS/SSL,howeverthesslmoduleinPythonisnotavailable.1.Ope......
  • Python爬虫获取校园课表(强制系统举例)
    Http:超文本传输协议Https:安全的http首先引入request库:pipinstallrequests 先F12打开页面检查,在network(网络)里面,然后刷新页面,会发先有个请求文档,点击并观察它:在常规里面可以看到请求地址为https://www.paisi.edu.cn:8181/jsxsd/?tdsourcetag=s_pcqq_aiomsg,将它复制到......
  • Python_Gui_tkinker学习笔记
    #-*-coding:utf-8-*-importtkinterastk创建主窗口#调用Tk()创建主窗口root_window=tk.Tk()窗口名字#给主窗口起一个名字,也就是窗口的名字root_window.title('C语言中文网:c.biancheng.net')打开窗口#开启主循环,让窗口处于显示状态root_window.mainloop()创......
  • Python和C++之间
    编程语言编程语言创造来都是为了解决实际问题的了解一门第二,甚至第三语言。因为只有你了解了不同工具的特性,以及它们擅长解决的问题,你才能更高效地在日常工作中运用它们。为问题选择正确的语言/工具/解决方案,将能大大减少解决问题所需的工作量训练你习惯跳出一种语言或范式的......
  • Python函数
    【一】函数的定义和使用函数可以提高代码可读性方便维护函数的使用必须遵循’先定义,后调用’的原则。函数的定义就相当于事先将函数体代码保存起来,然后将内存地址赋值给函数名,函数名就是对这段代码的引用,这和变量的定义是相似的。没有事先定义函数而直接调用,就相当于......
  • 使用Python合并多个Excel文件
    合并Excel可以将多个文件中的数据合并到一个文件中,这样可以帮助我们更好地汇总和管理数据。日常工作中,合并Excel主要有以下两种需求:将多个Excel文件合并为一个文件将多个Excel工作表合并为一个工作表这篇文章将介绍如何使用第三方Python库Spire.XLSforPython实现以上两种......
  • 扫描并清除重复文件的Python脚本
    电脑里存的照片越来越多,其中有很多是重复的。如果依赖人边去一张一张对比,需要的工作量太大了。下面的Python脚本在一个目录树上递归地对所有文件作MD5校验,将重复的文件找出来。保留用户指定的文件,将多余的文件全部删除掉。#!/usr/bin/envpython3importsysimporthashlibim......
  • node调用python输出中文乱码问题
    问题描述使用node的children_process模块调用python脚本文件,出现输出信息为乱码问题//node脚本const{spawn}=require('child_process');constpythonProcess=spawn('python',['./test.python']);pythonProcess.stdout.on('data',(data)=>{......
  • Python_数据结构的应用heap
    数据结构栈-->stack队列-->queue树-->tree堆-->heap散列-->hash图-->graph图结构一般包括顶点和边邻接矩阵DAG,DirectedAcyclicGraph即「有向无环图」树树(Tree)是一种非线性的数据结构,由n个节点组成,其中每个节点都有零个或多个子节点。......