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

Python92

全局空间和局部空间

命名空间

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

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

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

创建和销毁顺序

  • 创建顺序:
  • 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__': , '__spec__': None, '__annotations__': {}, '__builtins__': , '__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__': , '__spec__': None, '__annotations__': {}, '__builtins__': , '__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__': , '__spec__': None, '__annotations__': {}, '__builtins__': , '__file__': 'E:/0-project/python/mymsr/ceshi/test6.py', '__cached__': None, 'a': 1, 'b': 2, 'c': 3, 'func': }
'''

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

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

globals可以动态创建全局变量

dic = globals()

print(dic)  # 返回系统的字典
'''
结果:
{'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__': , '__spec__': None, '__annotations__': {}, '__builtins__': , '__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__': , '__spec__': None, '__annotations__': {}, '__builtins__': , '__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__': , '__spec__': None, '__annotations__': {}, '__builtins__': , '__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__': , '__spec__': None, '__annotations__': {}, '__builtins__': , '__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):当前函数内的作用域           (局部作用域)

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

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之后,获取的是调用之前的所用变量,返回字典,全局作用域

Original: https://www.cnblogs.com/msr20666/p/16101151.html
Author: 小小垂髫
Title: Python 函数进阶-全局空间和局部空间



相关阅读

Title: drf -- 重新封装的请求类方法和响应类

1.请求类的新方法

request.query_params方法的使用

  • 类似request.GET
  • 代码示例:
from rest_framework.views import APIView
from rest_framework.response import Response

class StudentAPIView(APIView):

    def get(self,request):
        #访问该接口时传入参数:?user=chen&love=123&love=345
        print(request.query_params)#&#x6253;&#x5370;&#x7ED3;&#x679C;&#xFF1A;<querydict: {'uesr': ['chen'], 'love': ['123', '345']}>
        #&#x53EF;&#x901A;&#x8FC7;get&#x6216;&#x8005;getlist&#x65B9;&#x6CD5;&#x83B7;&#x53D6;&#x53C2;&#x6570;&#x91CC;&#x9762;&#x7684;&#x503C;
        print(request.query_params.get('user')) #&#x6253;&#x5370;&#x7ED3;&#x679C;&#xFF1A;chen
        print(request.query_params.getlist('love')) #&#x6253;&#x5370;&#x7ED3;&#x679C;&#xFF1A;['123', '345']
        return Response('ok')
</querydict:>

request.data方法的使用

  • 类似于request.POST和request.FILES的集合体
  • 代码示例:
from rest_framework.views import APIView
from rest_framework.response import Response
class StudentAPIView(APIView):
    def post(self,request):

        data = request.data
        #request.data&#x5305;&#x542B;&#x4E86;request.POST,request.FILES&#x7684;&#x529F;&#x80FD;&#xFF0C;&#x8FD8;&#x53EF;&#x4EE5;&#x7528;&#x6765;&#x63A5;&#x6536;&#x6587;&#x4EF6;
        #&#x4E0A;&#x4F20;&#x7684;&#x6587;&#x4EF6;&#xFF0C;&#x4F1A;&#x5B58;&#x5728;&#x5185;&#x5B58;&#x5730;&#x5740;&#x4E2D;
        print(data) #&#x6253;&#x5370;&#x7ED3;&#x679C;&#xFF1A;<querydict: {'name': ['chen'], '图片': [<inmemoryuploadedfile: capture001.png (image png)>]}>

        return Response('ok')

</querydict:>

新封装的响应类

  • 必须继承新的视图类 APIView
from rest_framework.views import APIView
from rest_framework.response import Response
class StudentAPIView(APIView):
    def post(self,request):

        data = request.data
        #request.data&#x5305;&#x542B;&#x4E86;request.POST,request.FILES&#x7684;&#x529F;&#x80FD;&#xFF0C;&#x8FD8;&#x53EF;&#x4EE5;&#x7528;&#x6765;&#x63A5;&#x6536;&#x6587;&#x4EF6;
        #&#x4E0A;&#x4F20;&#x7684;&#x6587;&#x4EF6;&#xFF0C;&#x4F1A;&#x5B58;&#x5728;&#x5185;&#x5B58;&#x5730;&#x5740;&#x4E2D;
        print(data) #&#x6253;&#x5370;&#x7ED3;&#x679C;&#xFF1A;<querydict: {'name': ['chen'], '图片': [<inmemoryuploadedfile: capture001.png (image png)>]}>
        from rest_framework import status  # &#x5BFC;&#x5165;&#x8BE5;&#x7C7B;&#xFF0C;&#x53EF;&#x4EE5;&#x8BBE;&#x7F6E;&#x4E00;&#x4E2A;&#x6709;&#x89E3;&#x91CA;&#x7684;&#x72B6;&#x6001;&#x7801;
        res = Response('ok',status=status.HTTP_200_OK)
        res.set_cookie("id",'123') #&#x53EF;&#x4EE5;&#x5728;&#x8FD4;&#x56DE;&#x4E4B;&#x524D;&#x8BBE;&#x7F6E;&#x4E00;&#x4E2A;cookie
        res['xxxx'] = 'xxoo' #&#x53EF;&#x4EE5;&#x8BBE;&#x7F6E;&#x4E00;&#x4E2A;&#x54CD;&#x5E94;&#x5934;
   #-------------status&#x4E2D;&#x5C01;&#x88C5;&#x7684;&#x54CD;&#x5E94;&#x72B6;&#x6001;&#x7801;-------------------
        '''
        HTTP_100_CONTINUE = 100
        HTTP_101_SWITCHING_PROTOCOLS = 101
        HTTP_200_OK = 200
        HTTP_201_CREATED = 201
        HTTP_202_ACCEPTED = 202
        HTTP_203_NON_AUTHORITATIVE_INFORMATION = 203
        HTTP_204_NO_CONTENT = 204
        HTTP_205_RESET_CONTENT = 205
        HTTP_206_PARTIAL_CONTENT = 206
        HTTP_207_MULTI_STATUS = 207
        HTTP_208_ALREADY_REPORTED = 208
        HTTP_226_IM_USED = 226
        HTTP_300_MULTIPLE_CHOICES = 300
        HTTP_301_MOVED_PERMANENTLY = 301
        HTTP_302_FOUND = 302
        HTTP_303_SEE_OTHER = 303
        HTTP_304_NOT_MODIFIED = 304
        HTTP_305_USE_PROXY = 305
        HTTP_306_RESERVED = 306
        HTTP_307_TEMPORARY_REDIRECT = 307
        HTTP_308_PERMANENT_REDIRECT = 308
        HTTP_400_BAD_REQUEST = 400
        HTTP_401_UNAUTHORIZED = 401
        HTTP_402_PAYMENT_REQUIRED = 402
        HTTP_403_FORBIDDEN = 403
        HTTP_404_NOT_FOUND = 404
        HTTP_405_METHOD_NOT_ALLOWED = 405
        HTTP_406_NOT_ACCEPTABLE = 406
        HTTP_407_PROXY_AUTHENTICATION_REQUIRED = 407
        HTTP_408_REQUEST_TIMEOUT = 408
        HTTP_409_CONFLICT = 409
        HTTP_410_GONE = 410
        HTTP_411_LENGTH_REQUIRED = 411
        HTTP_412_PRECONDITION_FAILED = 412
        HTTP_413_REQUEST_ENTITY_TOO_LARGE = 413
        HTTP_414_REQUEST_URI_TOO_LONG = 414
        HTTP_415_UNSUPPORTED_MEDIA_TYPE = 415
        HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE = 416
        HTTP_417_EXPECTATION_FAILED = 417
        HTTP_418_IM_A_TEAPOT = 418
        HTTP_422_UNPROCESSABLE_ENTITY = 422
        HTTP_423_LOCKED = 423
        HTTP_424_FAILED_DEPENDENCY = 424
        HTTP_426_UPGRADE_REQUIRED = 426
        HTTP_428_PRECONDITION_REQUIRED = 428
        HTTP_429_TOO_MANY_REQUESTS = 429
        HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE = 431
        HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS = 451
        HTTP_500_INTERNAL_SERVER_ERROR = 500
        HTTP_501_NOT_IMPLEMENTED = 501
        HTTP_502_BAD_GATEWAY = 502
        HTTP_503_SERVICE_UNAVAILABLE = 503
        HTTP_504_GATEWAY_TIMEOUT = 504
        HTTP_505_HTTP_VERSION_NOT_SUPPORTED = 505
        HTTP_506_VARIANT_ALSO_NEGOTIATES = 506
        HTTP_507_INSUFFICIENT_STORAGE = 507
        HTTP_508_LOOP_DETECTED = 508
        HTTP_509_BANDWIDTH_LIMIT_EXCEEDED = 509
        HTTP_510_NOT_EXTENDED = 510
        HTTP_511_NETWORK_AUTHENTICATION_REQUIRED = 511
        '''
        return res
</querydict:>

Original: https://www.cnblogs.com/zhiqianggege/p/16219792.html
Author: 志强爱璇璇
Title: drf -- 重新封装的请求类方法和响应类