python函數名稱空間與做用域、閉包

1、命名空間概念

一、命名空間(name space)

  名稱空間是存放名字的地方。python

  若變量x=1,1存放在內存中,命名空間是存放名字x、x與1綁定關係的地方。閉包

二、名稱空間加載順序

python test.py
#一、python解釋器先啓動,於是首先加載的是:內置名稱空間
#二、執行test.py文件,而後以文件爲基礎,加載全局名稱空間
#三、在執行文件的過程當中若是調用函數,則臨時產生局部名稱空間

三、名字的查找順序

  局部名稱空間——》全局名稱空間——》內置名稱空間函數

  須要注意的是:在全局沒法查看局部的,在局部能夠查看全局的,以下例:ui

# max=1
def f1():
    # max=2
    def f2():
        max=3
        print(max)
    f2()
f1()
print(max)
"""
3
<built-in function max>
"""

max=1
def f1():
    # max=2
    def f2():
        # max=3
        print(max)
    f2()
f1()
print(max)
"""
1
1
"""

2、做用域  

  python中一個函數就是一個做用域,局部變量放置在其做用域中;代碼定義完成後,做用域已經完成,做用域鏈向上查找。相似C#、Java中做用域{}。url

  不一樣變量的做用域不一樣就是由這個變量所在的命名空間決定的。spa

一、做用域即範圍

  全局範圍(內置名稱空間與全局名稱空間屬於該範圍):全局存活,全局有效
  局部範圍(局部名稱空間屬於該範圍):臨時存活,局部有效code

二、做用域關係是在函數定義階段就已經固定的,與函數的調用位置無關,以下:

x=1
def f1():
    def f2():
        print(x)
    return f2

x=100
def f3(func):
    x=2
    func()

x=10000
f3(f1())
"""
10000
"""

三、查看做用域

LEGB 表明名字查找順序locals ——>enclosing(相鄰的上一級) ——>globals ——> __builtins__
  • locals 是函數內的名字空間,包括局部變量和形參
  • enclosing 外部嵌套函數的名字空間
  • globals 全局變量,函數定義所在模塊的名字空間
  • builtins 內置模塊的名字空間
n = 10
def fun1():
    n = 20
    print('func1',n)

    def fun2():
        n = 30
        print('func2',n)

        def func3():
            print("func3",n)    # locals沒有,先找相鄰上一級做用域
        func3()  # 30
    fun2()  # 30  
fun1()  # 20

   依次輸出:func1 20  ;func2 30  ; func3 30對象

def func():
    level = 'L1'
    n = 33
    print(locals())

    def outer():
        n = 44
        level = 'L2'
        print(locals(), n)

        def inner():
            level = 'L3'
            print(locals(), n)

        inner()  # {'n': 44, 'level': 'L3'} 44

    outer()  # {'n': 44, 'level': 'L2'} 44


func()  # {'n': 33, 'level': 'L1'}

  輸出以下結果:blog

{'n': 33, 'level': 'L1'}
{'level': 'L2', 'n': 44} 44
{'level': 'L3', 'n': 44} 44

3、閉包函數

  內部函數包含對外部做用域而非全局做用域的引用。以前都是經過參數將外部的值傳給函數,閉包提供的思路是將參數包起來。內存

一、什麼是閉包?

  閉包,即函數定義和函數表達式位於另外一個函數的函數體內(嵌套函數)。並且,這些內部函數能夠訪問它們所在的外部函數中聲明的全部局部變量、參數。當其中一個這樣的內部函數在包含它們的外部函數以外被調用時,就會造成閉包。

  也就是說,內部函數會在外部函數返回後被執行。而當這個內部函數執行時,它仍然必需訪問其外部函數的局部變量、參數以及其餘內部函數。這些局部變量、參數和函數聲明(最初時)的值是外部函數返回時的值,但也會受到內部函數的影響。

def func():
    n = 10

    def func2():
        print("func2:",n)  # 對外部做用域的引用
    return func2

f = func()  # 拿到func2內存地址
print(f)  # func2內存地址:<function func.<locals>.func2 at 0x101fb4620>
f()   # 執行func2: 10

  在外部能夠執行內部的函數,而且可使用內部函數做用域裏的值,這種現象就是閉包

  在函數裏面套了一層子函數,在外層函數被執行的時候,子函數被返回了,返回的是內存地址,在外面執行子函數的時候用引用了外層函數的變量,至關於二者有一種扯不掉理還亂的關係。

二、閉包的意義和應用

  閉包的意義:返回的函數對象,不只僅是一個函數對象,在該函數外還包裹了一層做用域,這使得,該函數不管在何處調用,優先使用本身外層包裹的做用域。

  應用領域:延遲計算(原來咱們是傳參,如今是抱起來)、裝飾器

from urllib.request import urlopen

def index(url):
    def get():
        return urlopen(url).read()

    return get


baidu = index('http://www.baidu.com')
print(baidu().decode('utf-8'))

4、函數嵌套返回值

age = 18
def func1():
    age = 73
    def func2():
        age = 84
        print(age)

    return 666

val = func1()
print(val)
'''
輸出:666
'''

 函數能夠當作返回值:

# 函數名能夠看成返回值
age = 18
def func1():
    age = 73
    def func2():...
    return func2   # 返回一個函數名# val = func1()
print(val)
'''
輸出:<function func1.<locals>.func2 at 0x101462598>
'''

# 代碼寫完以後做用域已經生成,無論函數名傳到哪裏,只要執行都回回定義的地方往上找
age = 18
def func1():
    age = 73
    def func2():
        print(age)
    return func2   # 返回一個函數名不帶括號

val = func1()
val()
'''
輸出結果:73
'''
相關文章
相關標籤/搜索