03-python语法之名称空间与作用域

名称空间与作用域

  • 参考引用资料:
    • https://zhuanlan.zhihu.com/p/108924801

名称空间—namespace

  • 对栈区的划分,是存放名字的地方;划分名称空间以后,就可以在栈区中存放相同的名字

三种名称空间用途与存活期

  • 内置名称空间
    • 存放python解释器内置的名字
    • python解释器启动则产生,python解释器关闭则销毁
>>> max
<built-in function max> #built-in内建
  • 全局名称空间
    • 存放顶级代码所产生的名字,只要不是函数内定义的、也不是内置名称空间的,剩下的都是全局名称空间
    • 运行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
  • 局部名称空间
    • 在调用函数时,运行函数体代码过程中产生的函数内的名字,比如函数的形参、函数内定义的名字都会被存放于该名称空间中
    • 调用函数时存活,调用完毕则销毁
def foo(x):
    y=3 #调用函数时,才会执行函数代码,名字x和y都存放于该函数的局部名称空间中

三种名称空间加载顺序

  • 加载顺序:内置名称空间->全局名称空间->局部名称空间
  • 销毁顺序:局部名称空间->全局名称空间->内置名称空间

三种名称空间查找名字的优先级

  • 从当前所在位置,向上一层层顺序为:
    • 局部名称空间->全局名称空间->内置名称空间。

作用域

全局作用域

  • 全局作用域:位于全局名称空间、内建名称空间中的名字属于全局范围
  • 该范围内的名字全局存活(除非被删除,否则在整个文件执行过程中存活)、全局有效(在任意位置都可以使用);

局部作用域

  • 局部作用域:位于局部名称空间中的名字属于局部范围。该范围内的名字临时存活(即在函数调用时临时生成,函数调用结束后就释放)、局部有效(只能在函数内使用)。
  • global

 

  • local

 

作用域与名字的查找关系

  • 在局部作用域查找名字时,起始位置是局部作用域,所以先查找局部名称空间,没有找到,再去全局作用域查找:先查找全局名称空间,没有找到,再查找内置名称空间,最后都没有找到就会抛出异常
x=100 #全局作用域的名字x
def foo():
    x=300 #局部作用域的名字x
    print(x) #在局部找x
foo()#结果为300
  • 在全局作用域查找名字时,起始位置便是全局作用域,所以先查找全局名称空间,没有找到,再查找内置名称空间,最后都没有找到就会抛出异常
x=100
def foo():
    x=300 #在函数调用时产生局部作用域的名字x
foo()
print(x) #在全局找x,结果为100

提示:调用内建函数locals()和globals()来分别查看局部作用域和全局作用域的名字,查看的结果都是字典格式。在全局作用域查看到的locals()的结果等于globals()

  • 在函数内,无论嵌套多少层,都可以查看到全局作用域的名字,若要在函数内修改全局名称空间中名字的值,当值为不可变类型时,则需要用到global关键字
x=1
def foo():
    global x #声明x为全局名称空间的名字
    x=2
foo()
print(x) #结果为2
  • 对于嵌套多层的函数,使用nonlocal关键字可以将名字声明为来自外部嵌套函数定义的作用域(非全局)
def  f1():
    x=2
    def f2():
        nonlocal x
        x=3
    f2() #调用f2(),修改f1作用域中名字x的值
    print(x) #在f1作用域查看x

f1()

#结果
3

 

函数对象

函数对象的特性

  • 函数可以被引用
>>> def add(x,y):
...     return x+y
... 
>>> func=add
>>> func(1,2)
3
  • 函数可以作为容器类型的元素
>>> dic={'add':add,'max':max}
>>> dic
{'add': <function add at 0x100661e18>, 'max': <built-in function max>}
>>> dic['add'](1,2)
3
  • 函数可以作为参数传入另外一个函数
>>> def foo(x,y,func):
...     return func(x,y)
...
>>> foo(1,2,add)
3
  • 函数的返回值可以是一个函数
def bar(): 
     return add 
func=bar() 
func(1,2)
3 

 

 

闭包函数

  • 闭包函数=名称空间与作用域+ 函数嵌套+函数对象
  • 名字的查找关系,是以函数的定义阶段为准

什么是闭包函数

  • “闭”函数指的是该函数是内嵌函数
  • “包”函数指的是该函数包含对外层函数作用域的引用(非全局作用域)
  • 作用域的关系是在定义完函数时就已经被确定了的,与函数的调用位置无关。
x=1

def f1():
    def f2():
        print(x)

    return f2

def f3():
    x=3
    f2=f1() #调用f1()返回函数f2
    f2() #需要按照函数定义时的作用关系去执行,与调用位置无关

f3() #结果为1
  • 通过函数的closure属性,查看到闭包函数所包裹的外部变量
>>> func.__closure__
(<cell at 0x10212af78: int object at 0x10028cca0>,)
>>> func.__closure__[0].cell_contents
2
  • “闭”代表函数是内部的,“包”代表函数外’包裹’着对外层作用域的引用。
  • 因而无论在何处调用闭包函数,使用的仍然是包裹在其外层的变量。

闭包函数的应用场景

  • 为啥要学习闭包——》2种函数体传参的方式
  • 两种为函数体传值的方式:
    • 1、直接将值以参数的形式传入;
    • 2、将值包给函数
import requests

#方式一:
def get(url):
    return requests.get(url).text

#方式二:
def page(url):
    def get():
        return requests.get(url).text
    return get
  • 提示:requests模块是用来模拟浏览器向网站发送请求并将页面内容下载到本地,需要事先安装:pip3 install requests

 

如何定义闭包函数

 

posted @ 2022-03-19 23:33  西瓜的春天  阅读(15)  评论(0)    收藏  举报