名称空间和作用域

发布时间 2023-12-11 17:02:20作者: Formerly0^0

名称空间和作用域

1. 名称空间

# x = 3
# # 开辟一块内容空间存放变量值 3
# # 用变量名 x 去引用这块内存空间
# name = 'serein'
# print(x)
# del x
# print(x)

# 内建名称空间 : 伴随Python解释器的启动,自动加载的名称空间和变量名
# del max
# print(max([1, 2, 3, 4]))

# 全局名称空间 :伴随Python解释器的开始执行,在内建空间的基础上扩充出来的名称空间
# 自己定义的
# name = 'serein'
# 第三方导入的
# import random

# 局部名称空间 : 伴随着函数或者类的启动而加载的名称空间
# def index():
#     x = 3
#     print(x)
# index()
# print(x)

# 程序启动的加载顺序 :
# 从内建开始(Python解释器自带的名称空间)
# 其次全局(自己定义的变量名/函数名/类名)
# 最后局部(定义在函数/类内部的变量名/类名/函数名)

# 寻找一个变量名的加载顺序
# 先从局部开始找
# 局部找不到去全局找
# 全局还找不到就内建
# name = 'serein'
# def index():
#     print(name)

2.作用域

# 作用域

# 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
'''

# 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

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

# 定义在全局的变量,在本文件任意位置可调用该变量
# a = 2
#
#
# def fun1():
#     print("这是fun1打印的:", a)
#
#
# fun1()
# print(a)
#
# # 这是fun1打印的: 2
# # 2

# 全局作用域
name = 'serein'


# 【1】定义了一个外部函数叫 outer
def outer():
    # 局部作用域
    age = 18
    print(f'my name is {name},my age is {age}')

    # inner 函数 : 既然是函数,就是一串内存地址
    def inner():
        # 嵌套作用域
        sex = '男'
        print(f'my name is {name},my age is {age},my sex is {sex}')

    # print(sex)
    # 打印内部函数 inner 的内促地址
    print(f'这是 outer 函数内部的 inner 函数的类型 :>>>> {type(inner)} 内存地址 :>>>> {id(inner)}')  # 2143503136320
    # 返回的内容其实是 内层函数 inner 的内存地址
    return inner


inner = outer()
print(f'这是 outer 函数外部的 inner 函数的类型 :>>>> {type(inner)} 内存地址 :>>>> {id(inner)}')  # 2143503136320
inner()


# print(inner, type(inner), id(inner))
# <function outer.<locals>.inner at 0x000001F312BE3640> <class 'function'> 2143503136320
# inner()

# my name is serein,my age is 18
# 1625968883264
# <function outer.<locals>.inner at 0x0000017A934C3640> <class 'function'> 1625968883264
# my name is serein,my age is 18,my sex is 男

# 【1】全局作用域 :整个当前文件内的所有变量和变量名/函数名/类名 --- 必须先定义才能再调用
# 【2】局部作用域 :定义在外层函数内部/类的内部才能加载到的变量名/函数名/类名 --- 只能在局部内部才能使用
# 【3】嵌套作用域 :定义在内层函数内部的变量名/函数名/类名
# 【4】内建作用域 :随着Python程序启动而自动加载的名称空间


# 通过参数 func 接收外部的函数地址
def wrapper(func):
    def inner():
        # 第一部分:执行外部传入的函数之前执行的代码
        '''...'''
        # 第二部分:执行外部传入的函数地址(res接受外部函数的返回值,如果有返回值的情况下)
        # 第三部分:执行外部传入的函数之后执行的代码
        '''...'''
        res = func()
        return res

    return inner


def add():
    return 1 + 9


inner = wrapper(add)
res = inner()
print(res)

3. LEGB规则和两个关键字使用

name = 'formerly'

 def index():
     name = 'serein'
     age = 18
     print(name)
     print(f"这是局部的变量 :>>>> {locals()}")

 index()
 print(f"这是外部的变量 :>>>> {globals()}")

 num_list = []


 def index(num):
    num_list.append(num)
    return num_list


index(1)
index(2)
index(3)

 is_admin = False
 login_data = {'username':'','is_admin': False}


 def login():
     is_admin = True
     login_data['is_admin'] = True
     print(login_data)
     print(is_admin)
     print(locals())


 login()
 print(is_admin)
 print(login_data)
 print(globals())
  
 is_admin = False


 def login():
     # 如果想要修改全局的不可变数据类型就需要 global 关键字将内部需要修改的变量名提高成全局的才能生效
     global is_admin
     is_admin = True
     print(is_admin)


 login()
 print(is_admin)


is_admin = False


def fun1():
    a = 1

    def fun2():
        nonlocal a
        a = a + 1
        print(a)

    return fun2


fun2 = fun1()
fun2()

4.闭包函数

  • 闭包,简而言之就是将数据封装在一个包(区域)中,使用时再去里面取。(本质上 闭包是基于函数嵌套搞出来一个中特殊嵌套)
  • 内嵌函数包含对外部函数作用域(而非全局作用域)中变量的引用
# 定义全局变量
x = 1
def outer():
  x = 2
  def inner():
    print(x)
  return inner

func = outer()
func()

4.1如何查看闭包函数所在包裹的外部变量

# 定义全局变量
x = 1
def outer():
  x = 2
  def inner():
    print(x)
  return inner

func = outer()
func()

res_first = func.__closure__
print(res_first)  # (<cell at 0x1006ee680: int object at 0x10058c110>,)

print(dir(func.__closure__[0]))
'''
['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'cell_contents']
'''

# __closure__ 属性是一个元组,包含了函数闭包中的每个 cell 对象。每个 cell 对象都有一个 cell_contents 属性,它存储着相应的值。
res_second = func.__closure__[0].cell_contents
print(res_second)