Python 函数进阶-全局空间和局部空间

全局空间和局部空间

命名空间

命名空间的概念的提出是为了划分和控制变量是否可见,以及生存周期的长短;命名空间的作用范围叫做作用域。

划分一块区域保存所有数据,以字典的方式存储(变量与值形成映射关系)。一共三种。

  1. 内建命名空间:
    • 解释器启动时创建,直到解释器运行结束,生存周期最长;
  2. 全局命名空间:
    • 文件运行时创建,直到解释器运行结束,生存周期较长;
  3. 局部命名空间:
    • 数调用时,里面的局部变量才创建,调用结束后即释放,生存周期较短;

创建和销毁顺序

  • 创建顺序:
    • python解释器启动->创建内建命名空间->创建全局命名空间->创建局部命名空间
  • 销毁顺序:
    • 函数调用结束后->销毁函数对应的局部命名空间数据->销毁全局命名空间数据->销毁内建命名空间数据

全局变量和局部变量

什么是全局和局部变量

局部变量就是在函数内部定义的变量,局部变量所在的就是局部命名空间,作用域仅仅在函数内部可见,也就是说只能在函数内部使用。

# 在函数中创建的变量就是局部变量
def func():
   var = '局部变量'

# 局部变量不可以在非对应局部环境中使用
print(var)  # error, 该变量不存在

全局变量就是在函数外部定义的或者使用global在函数内部定义的变量,全局变量所在的命名空间就是全局命名空间,作用域横跨整个文件,就是说在整个文件中的任何一个地方都可以使用全局变量。

# 在全局环境中创建的变量就是全局变量
var = '全局变量'

def func():
	# 在局部中也可以使用全局变量
	print(var)  # 全局变量

func()

局部变量最好不要和全局变量同名,如果同名,在局部环境中就无法使用全局变量了。

var = '全局变量'

def func():
	# 先使用了全局变量
	print(var)  # error, 找不到该变量

	# 然后局部变量和全局变量同名,那么新的局部变量就会在局部空间中覆盖了全局变量的一切影响力,这就叫做局部变量修改了全局变量;
	# 这样的话导致在局部空间中无法在使用该全局变量,之前在局部空间中使用的该变量就成为了先调用后定义;导致出错。
	var = '局部变量'
	print(var)

func()

# 但是局部同名变量不会影响到全局变量的值
print(var)  # 全局变量


内置函数就是内建命名空间,指的是那些python中自带的、内置的函数。

作用域

局部变量作用域:在函数的内部

全局变量作用域:横跨整个文件

生命周期

内置变量 -> 全局变量 -> 局部变量

内置变量自python程序运行的时候开始,一直等到python程序结束之后才会释放;

全局变量自创建开始,一直到程序结束或者被清除才会释放;

局部变量字创建开始,一直到局部空间执行结束或者清除就会释放;

全局部函数和关键字的使用

函数

函数 作用
globals() 存放着全局作用域中的所有内容,以字典的形式返回
locals() 存放着当前作用域中的所有内容,以字典的形式返回
globals()

返回所有的全局作用域中的内容。

如果在全局,调用globals之后,获取的是打印之前的所有变量,返回字典,全局空间作用域;

# 定义一些全局变量
a, b, c = 1, 2, 3

# 调用globals函数
res = globals()

# 第一次打印,包含a b c
print(res)
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002DBDCA5D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}}
'''


# 再定义一些变量
d, e, f = 1, 2, 3

# 第二次打印,包含a b c d e f
print(res)
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000002DBDCA5D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}, 'd': 1, 'e': 2, 'f': 3}
'''

如果在局部,调用globals之后,获取的是调用之前的所用变量,返回字典,全局空间作用域;

# 定义一些全局变量
a, b, c = 1, 2, 3


# 在局部环境中使用globals函数
def func():
	res = globals()
	print(res)


# 调用函数
func()
'''
结果:不包含 d e f
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x000001E7C287D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'func': <function func at 0x000001E7C2772F28>}
'''


# 再定义一些全局变量
d, e, f = 4, 5, 6

# 第二次调用函数
func()
'''
结果:包含 d e f
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000021A3F3DD198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'func': <function func at 0x0000021A3F2D2F28>, 'd': 4, 'e': 5, 'f': 6}
'''

globals可以动态创建全局变量

dic = globals()

print(dic)  # 返回系统的字典
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000026F357ED198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'dic': {...}}
'''


# 在全局的字典当中,通过添加键值对,自动创建全局变量,对应的键是变量名,对应的值是变量指向的值
dic['msr123123123'] = '123456'

print(msr123123123)	# 123456

# 查看全局内容
print(dic)
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x00000161D944D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'dic': {...}, 'msr123123123': '123456'}
'''
locals()

返回当前所在作用域的所有内容。

如果在全局,调用locals之后,获取的是打印之前的所有变量,返回字典,全局空间作用域;

# 定义一些全局变量
a, b, c = 1, 2, 3

# 调用locals函数
res = locals()

# 第一次打印,包含a b c
print(res)
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000018C82A3D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test1.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}}
'''


# 再定义一些变量
d, e, f = 1, 2, 3

# 第二次打印,包含a b c d e f
print(res)
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': <_frozen_importlib_external.SourceFileLoader object at 0x0000018C82A3D198>, '__spec__': None, '__annotations__': {}, '__builtins__': <module 'builtins' (built-in)>, '__file__': 'E:/0-project/python/mymsr/ceshi/test1.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'res': {...}, 'd': 1, 'e': 2, 'f': 3}
'''

如果在局部,调用locals之后,获取的是调用之前的所有变量,返回字典,局部空间作用域;

# 定义一些局部变量
def func():
   # 局部变量
   aa, bb, cc = 11, 22, 33

   # 第一遍调用
   res = locals()

   # 第一次打印,包含 aa bb cc
   print(res)  # {'cc': 33, 'bb': 22, 'aa': 11}

   # 再定义一些局部变量
   dd, ee, ff = 44, 55, 66

   # 第二次打印,不包含 dd ee ff
   print(res)  # {'cc': 33, 'bb': 22, 'aa': 11}

   # 调用第二遍
   res2 = locals()

   # 打印第一次的调用,包含 dd ee ff
   print(res)  # {'cc': 33, 'bb': 22, 'aa': 11, 'ff': 66, 'ee': 55, 'dd': 44, 'res': {...}}
   
   # 打印第二次的调用,包含 dd ee ff
   print(res2) # {'cc': 33, 'bb': 22, 'aa': 11, 'ff': 66, 'ee': 55, 'dd': 44, 'res': {...}}

# 调用函数,返回在函数中的局部变量
func()

关键字

关键字 作用
global 声明全局变量、获取使用和修改全局变量的权限
nonlocal 修改局部变量(当前函数的上一层的局部变量)
global

在局部环境中创建的变量是局部变量,在全局环境中是不可以使用的。但是使用global定义的变量就是一个全局变量,这个变量可以全局环境中使用。

def func():
	var = '局部变量'

	global glvar
	glvar = '全局变量'

# 一定要执行局部环境哟
func()

# 全局环境中
print(var)  # error,局部变量不能调用
# 使用global定义的变量是全局变量
print(glvar)    # 全局变量

在局部环境中无法修改全局变量的值,使用global可以在局部环境中修改全局变量。

var = '全局变量'

def func():
	global var
	var = '局部环境中修改'

func()

print(var)  # 局部环境中修改

函数的嵌套

在学习nonlocal之前我们需要先学习一些关于函数嵌套的知识。

内函数和外函数

函数之间是可以互相嵌套的,外层的叫做外函数,内层的叫做内函数。

def outer():
	print('我叫outer,是外函数')

	def inner():
		print('我叫inner,在outer的里面,是内函数')

	# 在外函数中执行内函数
	inner()


# 执行外函数
outer()

'''
结果:
我叫outer,是外函数
我叫inner,在outer的里面,是内函数
'''
  1. 内函数不可以直接在外函数外执行调用
  2. 调用外函数后,内函数也不可以在函数外部调用
  3. 内函数只可以在外函数的内部调用
  4. 内函数在外函数内部调用时,有先后顺序,必须先定义在调用,因为python没有预读机制,这个预读机制适用于python中的所有场景。
# 外层是outer,内层是inner,最里层是smaller,调用smaller里的所有代码
def outer():
	print('我叫outer,是最外层函数,是inner和smaller的外函数')

	def inner():
		print('我叫inner,是outer的内函数,是smaller的外函数')

		def smaller():
			print('我叫smaller,是outer和inner的内函数')

		# 先在inner中执行smaller
		smaller()

	# 然后在outer中执行inner
	inner()

# 最后再执行outer才能执行smaller函数
outer()

'''
结果:
我叫outer,是最外层函数,是inner和smaller的外函数
我叫inner,是outer的内函数,是smaller的外函数
我叫smaller,是outer和inner的内函数
'''

我们在多个函数嵌套的时候要注意,不管外函数还是内函数,都是函数,只要是函数中的变量都是局部变量。

内涵可以使用外函数的局部变量,外函数不能直接使用内函数的局部变量。

LEGB原则

LEGB原则就是一个就近找变量原则,依据就近原则,从下往上,从里向外,依次寻找。

B————Builtin(Python):Python内置模块的命名空间    (内建作用域)
G————Global(module):函数外部所在的命名空间        (全局作用域)
E————Enclosing Function Locals:外部嵌套函数的作用域(嵌套作用域)
L————Local(Function):当前函数内的作用域           (局部作用域)

在这里插入图片描述

nonlocal

现在我们正式学习nonlocal关键字,nonlocal的作用是修改当前局部环境中上一层的局部变量。那么我们根据这个作用便知道了nonlocal的使用环境至少是一个二级的嵌套环境,且外层的局部环境中必须存在一个局部变量。

def outer():
    # 定义变量
	lvar = 'outer var'

	def inner():
        # 内函数使用nonlocal修改上一层的局部变量
		nonlocal lvar
		lvar = 'inner var'

    # 执行inner函数
	inner()
	print(lvar)

outer() # inner var

假如上一层的局部环境中没有这个变量怎么办,那么就根据LEGB原则向上寻找。

def outer():
	# 定义变量
	lvar = 'outer var'

	def inner():
		
		def smaller():
			
            # smaller中修改变量,但是inner中没有,就向上寻找修改outer中的变量
			nonlocal lvar
			lvar = 'smaller var'

		# 执行 smaller函数
		smaller()

	# 执行inner函数
	inner()
	print(lvar)

# 执行outer函数
outer()

如果层层寻找,直到最外层的函数中也没有这个变量,那么就会报错,因为nonlocal只会修改局部变量,如果超出范围,就会报错。

var = 1  # 变量在最外层的函数之外,也就是全局变量,nonlocal无法修改

def outer():

   def inner():

      def smaller():

         nonlocal var    # error,没有局部变量
         var = 2
         print(var)

      smaller()

   inner()

outer()

总结

全局变量和局部变量

局部环境中可以调用全局变量,但是不能修改(但是如果全局变量是可变数据则可以修改其中的值)
全局环境中不能调用局部变量 也不能修改

函数

global()

(在函数内部使用,可以对全局变量进行操作)
1、可以在局部环境中定义全局变量
2、可以在局部环境中修改全局变量

nonlocal()

(在内函数中使用,可以在内函数中修改外函数中的局部变量)

关键字

locals

1、locals获取当前作用域当中所有的变量
如果在全局调用locals之后,获取的是打印之前的所有变量,返回字典,全局作用域
如果在局部调用loclas之后,获取的是调用之前的所有变量,返回字典,局部作用域

globals

2、globals只获取全局空间中的所有变量
如果在全局调用globals之后,获取的是打印之前的所用变量,返回字典,全局作用域
如果在局部调用globals之后,获取的是调用之前的所用变量,返回字典,全局作用域

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Python 函数进阶-全局空间和局部空间 - Python技术站

(0)
上一篇 2023年4月2日 下午5:50
下一篇 2023年4月2日 下午5:50

相关文章

  • python常用标准库(时间模块time和datetime)

    常用的标准库 time时间模块 import time time — 获取本地时间戳 时间戳又被称之为是Unix时间戳,原本是在Unix系统中的计时工具。 它的含义是从1970年1月1日(UTC/GMT的午夜)开始所经过的秒数,不考虑闰秒。UNIX时间戳的 0 按照ISO 8601规范为 :1970-01-01T00:00:00Z。 比如: 时间戳 60 …

    Python开发 2023年4月2日
    00
  • python常用标准库(math数学模块和random随机模块)

    常用的标准库 数学模块 import math ceil — 上取整 对一个数向上取整(进一法),取相邻最近的两个整数的最大值。 import math res = math.ceil(4.1) print(res) # 5 floor — 下取整 对一个数向下取整(退一法),取相邻最近的两个整数的最小值。 import math res = math.…

    Python开发 2023年4月2日
    00
  • python常用标准库(os系统模块、shutil文件操作模块)

    常用的标准库 系统模块 import os 系统模块用于对系统进行操作。 常用方法 os模块的常用方法有数十种之多,本文中只选出最常用的几种,其余的还有权限操作、文件的删除创建等详细资料可以参考官方文档。 system — 执行系统命令 参数的数据类型是字符串格式,内容是系统指令。执行时,直接返回系统输出。 import os os.system(‘ifc…

    Python开发 2023年4月2日
    00
  • Python 函数进阶-高阶函数

    高阶函数 什么是高阶函数 高阶函数就是能够把函数当成参数传递的函数就是高阶函数,换句话说如果一个函数的参数是函数,那么这个函数就是一个高阶函数。 高阶函数可以是你使用def关键字自定义的函数,也有Python系统自带的内置高阶函数。 自定义一个高阶函数 我们下面的例子中,函数 senior 的参数中有一个是函数,那么senior就是一个高阶函数;函数 ten…

    Python开发 2023年4月2日
    00
  • python常用内置函数和关键字

    常用内置方法 在Python中有许许多多的内置方法,就是一些Python内置的函数,它们是我们日常中经常可以使用的到的一些基础的工具,可以方便我们的工作。 查看所有的内置类和内置方法 # 方法一 built_list = dir(__builtins__) # 方法二 import builtins built_list = dir(builtins) 其中…

    Python开发 2023年4月2日
    00
  • Python常用标准库(pickle序列化和JSON序列化)

    常用的标准库 序列化模块 import pickle 序列化和反序列化 把不能直接存储的数据变得可存储,这个过程叫做序列化。把文件中的数据拿出来,回复称原来的数据类型,这个过程叫做反序列化。 在文件中存储的数据只能是字符串,或者是字节流,不能是其它的数据类型,但是如果想要将其存储就需要序列化。 Python中的序列化模块叫做 pickle,PHP等其它的一些…

    Python开发 2023年4月2日
    00
  • python生成器

    生成器 我们学习完推导式之后发现,推导式就是在容器中使用一个for循环而已,为什么没有元组推导式? 原因就是“元组推导式”的名字不是这样的,而是叫做生成器表达式。 什么是生成器 生成器表达式本质上就是一个迭代器,是定义迭代器的一种方式,是允许自定义逻辑的迭代器。生成器使用generator表示。 迭代器和生成器的区别 迭代器本身是系统内置的, 无法重写内置的…

    Python开发 2023年4月2日
    00
  • Python 函数进阶-递归函数

    递归函数 什么是递归函数 如果一个函数,可以自己调用自己,那么这个函数就是一个递归函数。 递归,递就是去,归就是回,递归就是一去一回的过程。 递归函数的条件 一般来说,递归需要边界条件,整个递归的结构中要有递归前进段和递归返回段。当边界条件不满足,递归前进,反之递归返回。就是说递归函数一定需要有边界条件来控制递归函数的前进和返回。 定义一个简单的递归函数 #…

    Python开发 2023年4月2日
    00
合作推广
合作推广
分享本页
返回顶部