欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python基礎(chǔ)教程之名稱空間以及作用域

 更新時(shí)間:2022年01月10日 11:52:42   作者:DgLink  
變量是擁有匹配對(duì)象的名字(標(biāo)識(shí)符),命名空間是一個(gè)包含了變量名稱們(鍵)和它們各自相應(yīng)的對(duì)象們(值)的字典,下面這篇文章主要給大家介紹了關(guān)于Python基礎(chǔ)教程之名稱空間以及作用域的相關(guān)資料,需要的朋友可以參考下

前言

所謂“基礎(chǔ)不狠,人站不穩(wěn)”,對(duì)于任何一種編程語(yǔ)言來(lái)說(shuō)基礎(chǔ)往往都是重中之重,以Python為例,其中的兩大分水嶺就是函數(shù)編程和面向?qū)ο?,而今天所要鞏固的知識(shí)點(diǎn)后續(xù)會(huì)多次使用,那就是名稱空間和作用域

名稱空間

什么是名稱空間

在Python中名稱空間是用存儲(chǔ)對(duì)象和名字綁定關(guān)系的地方,那么問(wèn)題來(lái)了,什么是對(duì)象,什么是名字,什么是綁定關(guān)系?

1)在目前,我們對(duì)于對(duì)象的認(rèn)知可以暫時(shí)只停留在人云亦云的“Python中一切都是對(duì)象”基礎(chǔ)上,函數(shù)是對(duì)象、類是對(duì)象、變量,模塊、所有一切都是對(duì)象,有這樣的認(rèn)知就可以了,后續(xù)有機(jī)會(huì)將繼續(xù)補(bǔ)充;

2)名字,很簡(jiǎn)單,每一次我們對(duì)模塊、變量、函數(shù)、類的定義都需要取名字,而這些名字都會(huì)放在名稱空間之中;

3)Python對(duì)于名字和數(shù)據(jù)之間給出了綁定關(guān)系,舉個(gè)例子,當(dāng)我們?cè)诙xa = 6時(shí),Python就自動(dòng)將變量a這個(gè)名字與6這個(gè)對(duì)象給出了綁定關(guān)系,我們可以使用del語(yǔ)句將綁定關(guān)系解除。

明白了名稱空間是用于存儲(chǔ)對(duì)象和名字綁定關(guān)系的地方,那么接下來(lái)就可以細(xì)致了解一下名稱空間可以分為哪幾類了:

1)內(nèi)置名稱空間 —— 用于存放各種內(nèi)置函數(shù)(built-in functions)、內(nèi)置模塊(built-in modules),例如abs()就是內(nèi)置函數(shù),內(nèi)置名稱空間可以在Python任何一處使用;

2)全局名稱空間 —— 全局名稱空間中的名字可以在同一個(gè)模塊中任意處使用;

3)局部名稱空間 —— 局部名稱空間中的名字僅僅只能夠在函數(shù)內(nèi)部使用。

名稱空間的意義

名稱空間最大的作用就是防止名字重復(fù)造成的引用不當(dāng),我們可以在全局名稱空間中定義一個(gè)a = 6同時(shí)也可以在局部名稱空間中定義一個(gè)a = 7,這兩者之間是不會(huì)產(chǎn)生任何沖突的,這就是名稱空間最大的作用,防止名字重復(fù)造成的引用不當(dāng)。

名稱空間的查找順序

知道了名稱空間的意義,那么肯定會(huì)有讀者意識(shí)到,我在全局定義一個(gè)a = 6,在局部定義一個(gè)a = 7,那么接下來(lái)調(diào)用a這個(gè)名字的時(shí)候,Python究竟會(huì)從哪個(gè)空間開始尋找a所對(duì)應(yīng)的對(duì)象呢?

我只能說(shuō),這位讀者你很上道,我們將以實(shí)例解答這個(gè)問(wèn)題;

a = 6              # 在全局名稱空間中定義一個(gè)a
b = 8            # 在全局名稱空間中定義一個(gè)b,為了測(cè)驗(yàn)調(diào)用函數(shù)時(shí)能否找到全局中的b
def test():
    a = 7        # 在局部名稱空間中定義一個(gè)a
    return a,b
print(test())
print(a)    

(7,8)
6

從以上我們的測(cè)驗(yàn)中,調(diào)用函數(shù)test時(shí)輸出的a將會(huì)是7,而當(dāng)直接使用print(a)時(shí)輸出的a將會(huì)是6。

所以我們可以大膽的下結(jié)論:

1)當(dāng)調(diào)用函數(shù)的時(shí)候,函數(shù)尋找名字的順序?qū)?huì)是 局部名稱空間—>全局名稱空間—>內(nèi)置名稱空間;

2)當(dāng)沒(méi)有調(diào)用函數(shù),直接使用名字的時(shí)候查找順序就是 全局名稱空間 —>內(nèi)置名稱空間;

3)只要在某個(gè)名稱空間(局部也好、全局也罷)中找到了對(duì)應(yīng)的名字,就停止尋找;

4)在不同名稱空間中定義相同名字是可行的,后續(xù)定義的并不會(huì)將原先覆蓋掉。

局部名稱空間詳解

在局部名稱空間中有一個(gè)非常神奇的事情,因?yàn)楹瘮?shù)是可以相互嵌套的,在一個(gè)函數(shù)中嵌套另外一個(gè)函數(shù)是很正常的現(xiàn)象:

def test_1():           # 定義一個(gè)函數(shù)
    def test_2():       # 在test_1中定義一個(gè)嵌套函數(shù)
        print('球球好心人給個(gè)贊吧')
# 這是最簡(jiǎn)單的函數(shù)嵌套,
# 但也是最不規(guī)范的函數(shù)嵌套,
# 因?yàn)槿绻桓倪M(jìn)的話,則無(wú)法使用嵌套的test_2函數(shù)

以上就是最簡(jiǎn)單形式的函數(shù)嵌套,那么問(wèn)題接踵而至,上文中說(shuō)過(guò)局部命中空間是在函數(shù)中產(chǎn)生的,那么如果我在一個(gè)函數(shù)中定義一個(gè)嵌套函數(shù),是不是意味著我在局部名稱空間中創(chuàng)建了一個(gè)局部名稱空間?

對(duì)頭!

但是在術(shù)語(yǔ)上我們會(huì)稱test_2為最內(nèi)部名稱空間,而test_1則是被我們稱為附屬函數(shù)名稱空間;

我們可以如此反復(fù)俄羅斯套娃:

def test_1():           # 定義一個(gè)函數(shù)
    def test_2():       # 在test_1中定義一個(gè)嵌套函數(shù)
        def test_3():   # 在內(nèi)嵌函數(shù)test_2中再定義一個(gè)嵌套函數(shù)
            # 省略一萬(wàn)層....
            print('球球好心人給個(gè)贊吧')
        print('球球好心人給個(gè)贊吧')

嵌套函數(shù)中的查找順序

在前文中已經(jīng)介紹過(guò)了關(guān)于嵌套函數(shù)所產(chǎn)生的附屬函數(shù)名稱空間、內(nèi)部名稱空間,那么如果在附屬函數(shù)名稱空間和內(nèi)部名稱空間都定義一個(gè)相同名字,那么查找順序是如何呢?

b = 10                    # 在全局定義一個(gè)b
def test_1():           # 定義一個(gè)函數(shù)
    def test_2():       # 在test_1中定義一個(gè)嵌套函數(shù)
        a = 6           # 在內(nèi)部名稱空間中定義一個(gè)a
        return a,b
    a = 7                # 在附屬名稱空間中定義一個(gè)a
    b = 8               # 在附屬名稱空間中定義一個(gè)b
???????print(test_1())            # 調(diào)用函數(shù)

如果真的如上文中這樣寫的話,那么將不會(huì)輸出任何結(jié)果哦,因?yàn)槲覀冎徽{(diào)用了test_1,而作為嵌套的內(nèi)部函數(shù)test_2沒(méi)有被使用到,想要使用嵌套函數(shù)的話,就只能通過(guò)將嵌套函數(shù)作為返回值,返回出去

所以將代碼修改一下

b = 10                    # 在全局定義一個(gè)b
def test_1():           # 定義一個(gè)函數(shù)
    def test_2():       # 在test_1中定義一個(gè)嵌套函數(shù)
        a = 6           # 在內(nèi)部名稱空間中定義一個(gè)a
        return a,b
    a = 7                # 在附屬名稱空間中定義一個(gè)a
    b = 8               # 在附屬名稱空間中定義一個(gè)b
    return test_2
print(test_1()())        # 調(diào)用函數(shù)

10
(6,8)

按照修改后,我們所得到的結(jié)果將會(huì)是6,當(dāng)我們調(diào)用嵌套函數(shù)的時(shí)候,嵌套函數(shù)會(huì)從自身的局部空間中開始尋找是否有該名稱

就像調(diào)用嵌套函數(shù)test_2一般,它從自己的局部名稱空間開始尋找,找到了a = 6后就停止尋找

所以我們又可以下結(jié)論了:

1)當(dāng)調(diào)用嵌套函數(shù)的時(shí)候,它的查找順序是 內(nèi)部名稱空間—>附屬函數(shù)名稱空間—>全局名稱空間—>內(nèi)置名稱空間;

2)找到對(duì)應(yīng)的名字后就會(huì)停止尋找。

關(guān)于嵌套函數(shù)的使用

b = 10                    
def test_1():           
    def test_2():       
        a = 6           
        return a,b
    a = 7                
    b = 8               
    return test_2
print(test_1()())                # 仔細(xì)看一下調(diào)用函數(shù)的過(guò)程

為什么調(diào)用函數(shù)過(guò)程中需要寫兩個(gè)括號(hào)test_1()(),而不是直接test_1()呢?

我們仔細(xì)看一下test_1函數(shù)的返回值,test_1的返回值是一個(gè)函數(shù)對(duì)象test_2,所以我們?nèi)绻{(diào)用函數(shù)的話只寫一個(gè)括號(hào)將會(huì)得到一個(gè)函數(shù)對(duì)象,也就是test_2

來(lái)實(shí)例示范一下;

b = 10                    
def test_1():           
    def test_2():       
        a = 6           
        return a,b
    a = 7                
    b = 8               
    return test_2
print(test_1(), type(test_1()))        # 打印輸出一下結(jié)果

<function test_1..test_2 at 0x000001A8E9981F30> <class ‘function’>
以上就是打印輸出的結(jié)果,代表了函數(shù)對(duì)象

可能有讀者想要唱反調(diào)了,我就是想直接寫一個(gè)test_1()就能夠直接得到想要的結(jié)果該怎么辦呢?

我只能說(shuō),這位看官你很有成為天才的潛力,因?yàn)閼胁攀侨祟愡M(jìn)步的基石,這個(gè)需求可以實(shí)現(xiàn),但是我們要這樣改代碼:

b = 10                    
def test_1():           
    def test_2():       
        a = 6           
        return a,b
    a = 7                
    b = 8               
    return test_2()
print(test_1())                # 調(diào)用函數(shù)

(6,8)

我們的確得到了想要的結(jié)果,仔細(xì)想一下為什么呢?

還是因?yàn)榉祷刂担瘮?shù)test_1的返回值是test_2(),也就是說(shuō)返回的結(jié)果是函數(shù)test_2運(yùn)行后的結(jié)果,又開始俄羅斯套娃了,我拿到的返回值是另外一個(gè)函數(shù)的返回值???

我只能說(shuō)沒(méi)錯(cuò),是這樣的。

但是用這個(gè)方法需要注意一點(diǎn),那就是內(nèi)嵌函數(shù)必須是無(wú)參數(shù)的!

b = 10                    
def test_1():           
    def test_2(c):           # 隨便定義一個(gè)參數(shù)
        a = 6           
        return a,b
    a = 7                
    b = 8               
    return test_2()
print(test_1())                # 調(diào)用函數(shù)

TypeError: test_1..test_2() missing 1 required positional argument: ‘c’
這將會(huì)報(bào)錯(cuò),給出的錯(cuò)誤是函數(shù)test_2()缺失一個(gè)名為’c’的位置參數(shù)
所以想要使用這種方法還是需要注意下的,
但是換另外一種思路,如果內(nèi)嵌函數(shù)需要參數(shù),那么我返回的時(shí)候先把參數(shù)定義不行么?
這種方法的確是可行的,
但是如果這樣的話那不如直接使用默認(rèn)參數(shù),在定義的時(shí)候直接將參數(shù)c定義好

以上就是關(guān)于俄羅斯套娃的名稱空間的講解,接下來(lái)我們要介紹一下作用域了,如果能夠?qū)⒚Q空間中的知識(shí)點(diǎn)李姐,那么作用域也不過(guò)爾爾。

作用域

什么是作用域

作用域是根據(jù)名稱空間所產(chǎn)生的,意思就是名字的作用范圍;

在上文之中我們其實(shí)已經(jīng)或多或少涉及到了作用域了。

b = 10                            # 這個(gè)全局變量的作用域就是該模塊中的全部范圍        
def test_1():           
    def test_2():       
        a = 6           
        return a,b                # 正因?yàn)槿肿兞康淖饔糜谑侨糠秶?,才能夠返回b
    a = 7                
    b = 8               
    return test_2
print(test_1()())

或多或少讀者對(duì)于這個(gè)作用域已經(jīng)有些許了解,

我直接將結(jié)論擺出:

內(nèi)置名稱空間 —— 其作用域是Python中的所有模塊,能夠在所有的模塊中使用;
全局名稱空間 —— 其作用域是該模塊的所有范圍,能夠在模塊內(nèi)隨意使用;
局部名稱空間 —— 其作用域僅僅在于該函數(shù)內(nèi)部,只能夠在函數(shù)內(nèi)部使用。

可能正是因?yàn)樽饔糜虻牟煌?,所以查找順序也?huì)不同,作用域越大的名稱空間反而查找的優(yōu)先級(jí)越低,

正如上文中的,即使全局和局部中都有a這個(gè)名字,調(diào)用函數(shù)的時(shí)候也會(huì)先從局部開始。

global語(yǔ)句

不同的名稱空間可以定義相同的名字,這樣不會(huì)有任何沖突,可這也意味著,當(dāng)我們?cè)诰植棵Q空間的時(shí)候是無(wú)法修改全局中的名字綁定關(guān)系,于是Python提供了一個(gè)方法去解決這個(gè)問(wèn)題:

a = 10               # 定義一個(gè)全局語(yǔ)句

def test():
    global a        # 使用global語(yǔ)句,聲明我是用的名字a全局名稱空間中的那個(gè)a
    a = 5
    return a

print(a)            # 先打印輸出一下沒(méi)有調(diào)用函數(shù)前的a是什么
print(test())        # 輸出一下函數(shù)中的結(jié)果
print(a)            # 看一下全局中的a是否發(fā)生了改變

10
5
5

所以我們可以知道,使用global語(yǔ)句后,我們使用的名字都將會(huì)是全局名稱空間的

nonlocal語(yǔ)句

既然在局部可以修改全局名稱空間中的名字綁定關(guān)系,那么在內(nèi)部名稱空間是否可以修改附屬函數(shù)名稱空間中的綁定關(guān)系呢?

答案顯然是可以的,但是需要使用到nonlocal語(yǔ)句。

def test_1():
    def test_2():				# 在test_1里定義一個(gè)嵌套函數(shù)test_2
        a = 15

        def test_3():			# 俄羅斯套娃一波
            nonlocal a			# 使用nonlocal,聲明接下來(lái)使用的a是附屬名稱空間的a,所以究竟是test_2中的還是test_1中的?
            a = 5
            print('調(diào)用test_3對(duì)a這個(gè)名字的綁定關(guān)系進(jìn)行更改')

        test_3()
        print(f'輸出附屬函數(shù)名稱空間中的a:{a}')

    a = 10
    test_2()
    print(f'輸出最外部函數(shù)的a值:{a}')


test_1()

調(diào)用test_3對(duì)a這個(gè)名字的綁定關(guān)系進(jìn)行更改
輸出附屬函數(shù)名稱空間中的a:5
輸出最外部函數(shù)的a值:10

由此我們可以知道,在調(diào)用nonlocal聲明使用的a是函數(shù)test_2中的,而不是test_1中的

因此我們可以得出的結(jié)論是:

1)在使用nonlocal語(yǔ)句的過(guò)程中,僅僅只會(huì)向上尋找到對(duì)應(yīng)名字修改一次

題目題目

還是老規(guī)矩,寫一個(gè)題目對(duì)上述內(nèi)容進(jìn)行測(cè)試

def discount(price,rate):
    final_price = price * rate
    old_price = 6
    print('old_price的值',old_price)
    return final_price

old_price = float(input('請(qǐng)輸入價(jià)格'))
rate = float(input('請(qǐng)輸入折扣率'))
print(discount(old_price,rate))
print('old_price的值',old_price)

在上述代碼中,假設(shè)我輸入的old_price是100,rate是0.6
那么請(qǐng)問(wèn)兩個(gè)問(wèn)題

print(discount(old_price,rate))中會(huì)輸出的值是多少?
print('old_price的值',old_price)輸出的值是多少?

小結(jié)

  1. 命名空間是一個(gè)名字(變量)和對(duì)象的映射表。
  2. 作用域是指命名空間的作用范圍,或者說(shuō)管轄區(qū)域。
  3. 變量的查找遵循 LEGB 原則,先從基層(最內(nèi)層函數(shù)找),然后到市委(外層函數(shù))…,再到省委(模塊命名空間),最后到中央(builtin 命名空間)。
  4. 各個(gè)命名空間相互獨(dú)立,創(chuàng)建時(shí)間和生命周期各不相同。
  5. global 用于在函數(shù)內(nèi)創(chuàng)建和修改全局變量。
  6. nonlocal 用于在內(nèi)層函數(shù)修改外層函數(shù)局部變量。
  7. 沒(méi)有聲明 global 和 nonlocal,嘗試修改全局變量或外層函數(shù)局部變量,實(shí)際上只會(huì)在函數(shù)或者內(nèi)層函數(shù)創(chuàng)建一個(gè)新的局部變量,同名的全局變量或者外層函數(shù)局部變量不會(huì)受影響。

能夠看到這里的都是一條漢子!

總結(jié)

到此這篇關(guān)于Python基礎(chǔ)教程之名稱空間以及作用域的文章就介紹到這了,更多相關(guān)Python名稱空間及作用域內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 10分鐘快速入門Pandas庫(kù)

    10分鐘快速入門Pandas庫(kù)

    pandas?是基于NumPy?的一種工具,該工具是為解決數(shù)據(jù)分析任務(wù)而創(chuàng)建的,這篇文章主要介紹了10分鐘快速入門Pandas庫(kù),重點(diǎn)介紹pandas常見使用方法,結(jié)合實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2023-02-02
  • python簡(jiǎn)單利用字典破解zip文件口令

    python簡(jiǎn)單利用字典破解zip文件口令

    這篇文章主要給大家介紹了關(guān)于python簡(jiǎn)單利用字典破解zip文件口令的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-09-09
  • Python標(biāo)準(zhǔn)庫(kù)calendar的使用方法

    Python標(biāo)準(zhǔn)庫(kù)calendar的使用方法

    本文主要介紹了Python標(biāo)準(zhǔn)庫(kù)calendar的使用方法,calendar模塊主要由Calendar類與一些模塊方法構(gòu)成,Calendar類又衍生了一些子孫類來(lái)幫助我們實(shí)現(xiàn)一些特殊的功能,感興趣的可以了解一下
    2021-11-11
  • 解決python對(duì)齊錯(cuò)誤的方法

    解決python對(duì)齊錯(cuò)誤的方法

    在本篇文章里小編給大家整理的是關(guān)于python對(duì)齊錯(cuò)誤的解決方法,需要的朋友們可以參考學(xué)習(xí)下。
    2020-07-07
  • Python安裝Graphviz?超詳細(xì)圖文教程

    Python安裝Graphviz?超詳細(xì)圖文教程

    這篇文章主要介紹了Python安裝Graphviz?詳細(xì)教程,在Python安裝Graphviz畫圖器,首先要明確他是一個(gè)獨(dú)立的軟件,如果大家用pip的方法裝了graphviz可以先卸載,本文通過(guò)圖文并茂的形式詳細(xì)講解,需要的朋友參考下吧
    2023-02-02
  • numpy.bincount用于復(fù)數(shù)權(quán)重的方法

    numpy.bincount用于復(fù)數(shù)權(quán)重的方法

    numpy.bincount是NumPy庫(kù)中的一個(gè)函數(shù),它用于計(jì)算整數(shù)數(shù)組中每個(gè)值的出現(xiàn)次數(shù),numpy.bincount函數(shù)在統(tǒng)計(jì)整數(shù)數(shù)組中每個(gè)值的出現(xiàn)次數(shù)或權(quán)重和時(shí)非常有用,本文給大家介紹numpy.bincount如何用于復(fù)數(shù)權(quán)重,感興趣的朋友跟隨小編一起看看吧
    2023-11-11
  • Python對(duì)小數(shù)進(jìn)行除法運(yùn)算的正確方法示例

    Python對(duì)小數(shù)進(jìn)行除法運(yùn)算的正確方法示例

    這篇文章主要介紹了Python對(duì)小數(shù)進(jìn)行除法運(yùn)算的正確方法示例,正確的方法是需要轉(zhuǎn)換成浮點(diǎn)數(shù),否則永遠(yuǎn)不會(huì)得到正確結(jié)果,需要的朋友可以參考下
    2014-08-08
  • python深度學(xué)習(xí)之多標(biāo)簽分類器及pytorch實(shí)現(xiàn)源碼

    python深度學(xué)習(xí)之多標(biāo)簽分類器及pytorch實(shí)現(xiàn)源碼

    這篇文章主要為大家介紹了python深度學(xué)習(xí)之多標(biāo)簽分類器的使用說(shuō)明及pytorch的實(shí)現(xiàn)源碼,有需要的朋友可以借鑒參考下,希望能夠有所幫助
    2022-01-01
  • Python爬蟲之使用MongoDB存儲(chǔ)數(shù)據(jù)的實(shí)現(xiàn)

    Python爬蟲之使用MongoDB存儲(chǔ)數(shù)據(jù)的實(shí)現(xiàn)

    本文主要介紹了Python爬蟲之使用MongoDB存儲(chǔ)數(shù)據(jù)的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-06-06
  • pygame實(shí)現(xiàn)彈球游戲

    pygame實(shí)現(xiàn)彈球游戲

    這篇文章主要為大家詳細(xì)介紹了pygame實(shí)現(xiàn)彈球游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2020-04-04

最新評(píng)論