您好,登錄后才能下訂單哦!
這篇文章主要介紹了Python函數(shù)與參數(shù)實(shí)例代碼分析的相關(guān)知識,內(nèi)容詳細(xì)易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Python函數(shù)與參數(shù)實(shí)例代碼分析文章都會有所收獲,下面我們一起來看看吧。
函數(shù)是一個非常重要的概念,它們存在于所有編程語言中。函數(shù)允許我們定義一個動作(代碼塊),然后執(zhí)行該動作任意次數(shù),而無需遵循DRY原則重復(fù)自己。到目前為止,我一直在使用Python提供的一些內(nèi)置函數(shù),例如print
input
len
等。
什么是函數(shù)?函數(shù)(function)是用于完成特定任務(wù)的程序代碼的自包含單元。在面向?qū)ο缶幊痰念愔?,函?shù)通常被稱作方法。不同的函數(shù)在程序中扮演著不同的角色,起著不同的作用,執(zhí)行不同的動作。比如print()函數(shù)可以將對象打印到屏幕上;還有一些函數(shù)能夠返回一個值以供程序使用,比如len()將可計(jì)算長度的對象的元素個數(shù)返回給程序。
那么,為什么要使用函數(shù)呢?
第一、函數(shù)的使用可以重用代碼,省去重復(fù)性代碼的編寫,提高代碼的重復(fù)利用率。如果程序中需要多次使用某種特定的功能,那么只需要編寫一個合適的函數(shù)就可以了。程序可以在任何需要的地方調(diào)用該函數(shù),并且同一個函數(shù)可以在不同的程序中調(diào)用,就像我們經(jīng)常使用的print()和input()函數(shù)一樣。
第二、函數(shù)能封裝內(nèi)部實(shí)現(xiàn),保護(hù)內(nèi)部數(shù)據(jù),實(shí)現(xiàn)對用戶的透明。很多時候,我們把函數(shù)看做“黑盒子”,即對應(yīng)一定的輸入會產(chǎn)生特定的結(jié)果或返回某個對象。往往函數(shù)的使用者并不是函數(shù)的編寫者,函數(shù)的使用者對黑盒子的內(nèi)部行為并不需要考慮,可以把精力投入到自身業(yè)務(wù)邏輯的設(shè)計(jì)而不是函數(shù)的實(shí)現(xiàn)細(xì)節(jié)。只有函數(shù)的設(shè)計(jì)者或者說編寫者,才需要考慮函數(shù)內(nèi)部實(shí)現(xiàn)的細(xì)節(jié),如何暴露對外的接口,返回什么樣的數(shù)據(jù),也就是API的設(shè)計(jì)。
第三、即使某種功能在程序中只使用一次,將其以函數(shù)的形式實(shí)現(xiàn)也是有必要的,因?yàn)楹瘮?shù)使得程序模塊化,從“一團(tuán)散沙”變成“整齊方隊(duì)”,從而有利于程序的閱讀、調(diào)用、修改和完善。例如,假設(shè)你正在編寫一個實(shí)現(xiàn)下面功能的程序:
讀入一行數(shù)字
對數(shù)字進(jìn)行排序
找到它們的平均值
打印出一個柱狀圖
是時候創(chuàng)建一個函數(shù)了。
def blow_fire(): # 函數(shù)定義 print('fire ???? ???? ????') blow_fire() # 函數(shù)調(diào)用 blow_fire() # 可以調(diào)用多次
上面的函數(shù)看起來不錯吧,但它也有一些限制。它只能執(zhí)行相同的操作。讓我們使它更具可擴(kuò)展性,并通過向其傳遞一些數(shù)據(jù)來使其隨意執(zhí)行操作。
在定義函數(shù)時,當(dāng)我們向其提供一些數(shù)據(jù)以基于該數(shù)據(jù)執(zhí)行某些操作時,提供的數(shù)據(jù)稱為參數(shù)??梢詾楹瘮?shù)提供任意數(shù)量的參數(shù)。
絕大多數(shù)函數(shù)接收一定數(shù)量的參數(shù),然后根據(jù)實(shí)際調(diào)用時提供的參數(shù)的值的不同,輸出不同的結(jié)果。前面我們說過,將函數(shù)內(nèi)部的參數(shù)名字,定義得和外部變量的名字一樣是一種不好的習(xí)慣,它容易混淆思維,甚至發(fā)生錯誤。通常我們定義和給函數(shù)傳遞參數(shù)是這樣的:
x, y, z = 1, 2, 3 def add(a, b, c): return a+b+c add(x, y, x) # 使用變量,傳遞參數(shù) add(4, 5, 6) # 直接傳遞值也是可以的。
在上面的例子中,a,b,c叫做形式參數(shù),簡稱形參。而x,y,z和4,5,6叫做實(shí)際參數(shù),簡稱實(shí)參,也就是實(shí)際要傳遞的值。而我們通常討論的參數(shù),指的都是形參。
定義函數(shù)時,參數(shù)的名字和位置確定下來,函數(shù)的接口就固定了。對于函數(shù)的調(diào)用者來說,只需要知道如何傳遞正確的參數(shù),以及函數(shù)將返回什么樣的值就夠了,函數(shù)內(nèi)部的復(fù)雜邏輯被封裝起來,調(diào)用者無需了解。Python函數(shù)的參數(shù)定義靈活度非常大。除了正常定義的位置參數(shù)外,還可以使用默認(rèn)參數(shù)、動態(tài)參數(shù)和關(guān)鍵字參數(shù),這些都是形參的種類。
也叫必傳參數(shù),順序參數(shù),是最重要的,也是必須在調(diào)用函數(shù)時明確提供的參數(shù)!位置參數(shù)必須按先后順序,一一對應(yīng),個數(shù)不多不少的傳遞!
上面例子中的a,b,c就是位置參數(shù),我們在使用add(4, 5, 6)
調(diào)用時,就是將4傳給a,5傳給b,6傳給c的一一對應(yīng)傳遞。類似add(4, 5, 6, 7)
、add(4)
和add(5, 4, 6)
這種“畫蛇添足”、“缺胳膊少腿”和“嫁錯郎”類型的調(diào)用都是錯誤的。其中,add(5, 4, 6)
的調(diào)用在語法上沒問題,但是輸出結(jié)果可能和預(yù)期的不一致。
注意: Python在做函數(shù)參數(shù)傳遞的時候不會對數(shù)據(jù)類型進(jìn)行檢查,理論上你傳什么類型都可以!
def add(a, b, c): return a+b+c result = add("haha", 2, 3)
但是,上面的add函數(shù),如果你傳遞了一個字符串和兩個數(shù)字,結(jié)果是彈出異常,因?yàn)樽址疅o法和數(shù)字相加。這就是Python的弱數(shù)據(jù)類型和動態(tài)語言的特點(diǎn)。在簡單、方便的時候,需要你自己去實(shí)現(xiàn)數(shù)據(jù)類型檢查。
Traceback (most recent call last): File "F:/Python/pycharm/201705/func.py", line 33, in <module> result = add("haha", 2, 3) File "F:/Python/pycharm/201705/func.py", line 31, in add return a+b+c TypeError: must be str, not int
在函數(shù)定義時,如果給某個參數(shù)提供一個默認(rèn)值,這個參數(shù)就變成了默認(rèn)參數(shù),不再是位置參數(shù)了。在調(diào)用函數(shù)的時候,我們可以給默認(rèn)參數(shù)傳遞一個自定義的值,也可以使用默認(rèn)值。
def power(x, n = 2): return x**n ret1 = power(10) # 使用默認(rèn)的參數(shù)值n=2 ret2 = power(10, 4) # 將4傳給n,實(shí)際計(jì)算10**4的值
上面例子中的n就是個默認(rèn)參數(shù)。默認(rèn)參數(shù)可以簡化函數(shù)的調(diào)用,在為最常用的情況提供簡便調(diào)用的同時,還可以在特殊情況時傳遞新的值。但是在設(shè)置默認(rèn)參數(shù)時,有幾點(diǎn)要注意:
默認(rèn)參數(shù)必須在位置參數(shù)后面!
如果你違反了這點(diǎn),在語法層面直接是通不過的。
# 這是一個錯誤的例子 def power(n = 2,x): return x**n
當(dāng)有多個默認(rèn)參數(shù)的時候,通常將更常用的放在前面,變化較少的放后面。
def student(name, sex, age, classroom="101", tel="88880000", address="..."): pass
在調(diào)用函數(shù)的時候,盡量給實(shí)際參數(shù)提供默認(rèn)參數(shù)名。
def student(name, sex, age, classroom="101", tel="88880000", address="..."): pass student('jack','male',17) # 其它全部使用默認(rèn)值 student('tom','male',18,'102','666666','beijing') # 全部指定默認(rèn)參數(shù)的值 student('mary','female',18,'102',tel='666666') # 挑著來 student('mary','female',18,tel='666666','beijing') # 這是錯誤的參數(shù)傳遞方式 student("mary","female",18,tel="666666",address="beijing")
注意最后兩種調(diào)用方式,倒數(shù)第二種是錯誤的,而最后一種是正確的。為什么會這樣?因?yàn)橐磺袥]有提供參數(shù)名的實(shí)際參數(shù),都會當(dāng)做位置參數(shù)按順序從參數(shù)列表的左邊開頭往右匹配!
使用參數(shù)名傳遞參數(shù)
通常我們在調(diào)用函數(shù)時,位置參數(shù)都是按順序先后傳入,而且必須在默認(rèn)參數(shù)前面。但如果在位置參數(shù)傳遞時,給實(shí)參指定位置參數(shù)的參數(shù)名,那么位置參數(shù)也可以不按順序調(diào)用,例如:
def student(name, age, classroom, tel, address="..."): pass student(classroom=101, name="Jack", tel=66666666, age=20)
注意指定的參數(shù)名必須和位置參數(shù)的名字一樣。
默認(rèn)參數(shù)盡量指向不變的對象!
使用不可變的數(shù)據(jù)類型作為默認(rèn)值!
def func(a=None): # 注意下面的if語句 if a is None: a = [] a.append("A") return a print(func()) print(func()) print(func())
將默認(rèn)參數(shù)a設(shè)置為一個類似None,數(shù)字或字符串之類的不可變對象。在函數(shù)內(nèi)部,將它轉(zhuǎn)換為可變的類型,比如空列表。這樣一來,不管調(diào)用多少次,運(yùn)行結(jié)果都是['A']了。
顧名思義,動態(tài)參數(shù)就是傳入的參數(shù)的個數(shù)是動態(tài)的,可以是1個、2個到任意個,還可以是0個。在不需要的時候,你完全可以忽略動態(tài)函數(shù),不用給它傳遞任何值。
Python的動態(tài)參數(shù)有兩種,分別是*args
和**kwargs
,這里面的關(guān)鍵是一個和兩個星號的區(qū)別,而不是args
和kwargs
在名字上的區(qū)別,實(shí)際上你可以使用*any
或**whatever
的方式。但就如self一樣,默認(rèn)大家都使用*args
和**kwargs
。
注意:動態(tài)參數(shù),必須放在所有的位置參數(shù)和默認(rèn)參數(shù)后面!
def func(name, age, sex='male', *args, **kwargs): pass
一個星號表示接收任意個參數(shù)。調(diào)用時,會將實(shí)際參數(shù)打包成一個元組傳入形式參數(shù)。如果參數(shù)是個列表,會將整個列表當(dāng)做一個參數(shù)傳入。例如:
def func(*args): for arg in args: print(arg) func('a', 'b', 'c') li = [1, 2, 3] func(li)
運(yùn)行結(jié)果是:
a b c [1, 2, 3]
通過循環(huán)args,我們可以獲得傳遞的每個參數(shù)。但是li這個列表,我們本意是讓它內(nèi)部的1,2,3分別當(dāng)做參數(shù)傳遞進(jìn)去,但實(shí)際情況是列表本身被當(dāng)做一個整體給傳遞進(jìn)去了。怎么辦呢?使用一個星號!調(diào)用函數(shù),傳遞實(shí)參時,在列表前面添加一個星號就可以達(dá)到目的了。實(shí)際情況是,不光列表,任何序列類型數(shù)據(jù)對象,比如字符串、元組都可以通過這種方式將內(nèi)部元素逐一作為參數(shù),傳遞給函數(shù)。而字典,則會將所有的key逐一傳遞進(jìn)去。
def func(*args): for arg in args: print(arg) li = [1, 2, 3] func(*li)
兩個星表示接受鍵值對的動態(tài)參數(shù),數(shù)量任意。調(diào)用的時候會將實(shí)際參數(shù)打包成字典。例如:
def func(**kwargs): for kwg in kwargs: print(kwg, kwargs[kwg]) print(type(kwg)) func(k1='v1', k2=[0, 1, 2])
運(yùn)行結(jié)果是:
k1 v1 <class 'str'> k2 [0, 1, 2] <class 'str'>
而如果我們這樣傳遞一個字典dic呢?我們希望字典內(nèi)的鍵值對能夠像上面一樣被逐一傳入。
def func(**kwargs): for kwg in kwargs: print(kwg, kwargs[kwg]) dic = { 'k1': 'v1', 'k2': 'v2' } func(dic)
實(shí)際結(jié)果卻是彈出錯誤,為什么?
Traceback (most recent call last): File "F:/Python/pycharm/201705/func.py", line 10, in <module> func(dic) TypeError: func() takes 0 positional arguments but 1 was given
因?yàn)檫@時候,我們其實(shí)是把dic當(dāng)做一個位置參數(shù)傳遞給了func函數(shù)。而func函數(shù)并不接收任何位置函數(shù)。那怎么辦呢?使用兩個星號!
def func(**kwargs): for kwg in kwargs: print(kwg, kwargs[kwg]) dic = { 'k1': 'v1', 'k2': 'v2' } func(**dic)
有了前面一個星號的基礎(chǔ),這里我們應(yīng)該很好理解了。兩個星號能將字典內(nèi)部的鍵值對逐一傳入**kwargs
。
當(dāng)*args
和**kwargs
組合起來使用,理論上能接受任何形式和任意數(shù)量的參數(shù),在很多代碼中我們都能見到這種定義方式。需要注意的是,*args
必須出現(xiàn)在**kwargs
之前。
def func(*args, **kwargs): for arg in args: print(arg) for kwg in kwargs: print(kwg, kwargs[kwg]) lis = [1, 2, 3] dic = { 'k1': 'v1', 'k2': 'v2' } func(*lis, **dic)
現(xiàn)在我們結(jié)合一下普通參數(shù)和萬能參數(shù),看看會有什么情況發(fā)生:
def func(a, b, c=1, *args, **kwargs): for arg in args: print(arg) for kwg in kwargs: print(kwg, kwargs[kwg]) lis = ['aaa', 'bbb', 'ccc'] dic = { 'k1': 'v1', 'k2': 'v2' } func(1, 2, *lis, **dic)
打印結(jié)果是:
bbb ccc k1 v1 k2 v2
列表lis中的第一個元素‘a(chǎn)aa’怎么沒有打印出來?
我們改一下代碼,打印一下參數(shù)c的結(jié)果就知道了:
def func(a, b, c=1, *args, **kwargs): print('c的值是:', c) for arg in args: print(arg) for kwg in kwargs: print(kwg, kwargs[kwg]) lis = ['aaa', 'bbb', 'ccc'] dic = { 'k1': 'v1', 'k2': 'v2' } func(1, 2, *lis, **dic)
打印結(jié)果為:
c的值是: aaa bbb ccc k1 v1 k2 v2
原來,lis的第一個元素被傳遞給參數(shù)c了!這就是Python的參數(shù)傳遞規(guī)則之一。
對于*args
和**kwargs
參數(shù),函數(shù)的調(diào)用者可以傳入任意不受限制的參數(shù)。比如:
def func(*args): pass func("haha", 1, [], {}) func(1,2,3,4,5,6)
對于這樣的參數(shù)傳遞方式,雖然靈活性很大,但是風(fēng)險也很大,可控性差,必須自己對參數(shù)進(jìn)行過濾和判定。例如下面我只想要姓名、年齡和性別,就要自己寫代碼檢查:
def student(name, age, **kwargs): if 'sex' in kwargs: student_sex = kwargs['sex']
但是實(shí)際上,用戶任然可以隨意調(diào)用函數(shù),比如student("jack", 18, xxx='male')
,并且不會有任何錯誤發(fā)生。而我們實(shí)際期望的是類似student("jack", 18, sex='male')
的調(diào)用。那么如何實(shí)現(xiàn)這種想法呢?
可以用關(guān)鍵字參數(shù)!關(guān)鍵字參數(shù)前面需要一個特殊分隔符*
和位置參數(shù)及默認(rèn)參數(shù)分隔開來,*
后面的參數(shù)被視為關(guān)鍵字參數(shù)。在函數(shù)調(diào)用時,關(guān)鍵字參數(shù)必須傳入?yún)?shù)名,這和位置參數(shù)不同。如果沒有傳入?yún)?shù)名,調(diào)用將報錯。不同于默認(rèn)參數(shù),關(guān)鍵字參數(shù)必須傳遞,但是關(guān)鍵字參數(shù)也可以有缺省值,這時就可以不傳遞了,從而簡化調(diào)用。
我們把前面的函數(shù)改寫一下:
def student(name, age, *, sex): pass student(name="jack", age=18, sex='male')
注意函數(shù)的定義體首行。
如果函數(shù)定義中已經(jīng)有了一個*args
參數(shù),后面跟著的命名關(guān)鍵字參數(shù)就不再需要一個特殊分隔符*
了。
def student(name, age=10, *args, sex, classroom, **kwargs): pass student(name="jack", age=18, sex='male', classroom="202", k1="v1")
Python的函數(shù)參數(shù)種類多樣、形態(tài)多變,既可以實(shí)現(xiàn)簡單的調(diào)用,又可以傳入非常復(fù)雜的參數(shù)。需要我們多下功夫,多寫實(shí)際代碼,多做測試,逐步理清并熟練地使用參數(shù)。
return
是 Python 中的一個關(guān)鍵字,用于從函數(shù)返回值。為了使函數(shù)更有用,它需要根據(jù)表達(dá)式的計(jì)算返回一些值。如果未指定 return 語句,或者 return 語句的表達(dá)式的計(jì)算結(jié)果未計(jì)算為數(shù)據(jù)類型,則該函數(shù)將返回None
。在 JavaScript 世界中,這個None
可以鏈接到void
。
return
語句終止該函數(shù)并退出該函數(shù)。return
def multiplier(num1, num2): return num1 * num2 result = multiplier(2,3) print(result) # 6
是時候使用return
語句做一些很酷的事情了。
def sum(num1): def child(num2): return num1 + num2 return child add_10 = sum(10) print(add_10(20)) # 30 (Closure!!!) print(add_10(50)) # 60 print(add_10(100)) # 110
我剛剛驗(yàn)證了Python中也有閉包的概念,就像在JavaScript中一樣。它在創(chuàng)建工廠功能方面非常有效。在上面的代碼塊中,我能夠創(chuàng)建一個通用函數(shù)add_10,并向其傳遞動態(tài)參數(shù)以生成不同的結(jié)果。這是多么酷??!
下周將在學(xué)習(xí)Python中的函數(shù)式編程概念時對此進(jìn)行更多探討。
方法只是在對象內(nèi)部定義的函數(shù),或者換句話說,它們由對象“擁有”。使用對象名后跟
.
運(yùn)算符調(diào)用它們以執(zhí)行或調(diào)用它們。
return可以返回什么?
什么都不返回,僅僅return:return
數(shù)字/字符串/任意數(shù)據(jù)類型:return 'hello'
一個表達(dá)式:return 1+2
一個判斷語句:return 100 > 99
一個變量:return a
一個函數(shù)調(diào)用:return func()
甚至是返回自己?。?code>return self
多個返回值,以逗號分隔:return a, 1+2, "hello"
簡而言之,函數(shù)可以return幾乎任意Python對象。
在某些特定的位置,用三引號包括起來的部分,也被當(dāng)做注釋。但是,這種注釋有專門的作用,用于為__doc__提供文檔內(nèi)容,這些內(nèi)容可以通過現(xiàn)成的工具,自動收集起來,形成幫助文檔。比如,函數(shù)和類的說明文檔:
def func(a, b): """ 這個是函數(shù)的說明文檔。 :param a: 加數(shù) :param b: 加數(shù) :return: 和 """ return a + b class Foo: """ 這個類初始化了一個age變量 """ def __init__(self, age): self.age = age
需要強(qiáng)調(diào)的是這類注釋必須緊跟在定義體下面,不能在任意位置。
簡單來說,作用域意味著“我有權(quán)訪問哪些變量?這是解釋器在讀取代碼以查找變量范圍時提出的問題。在Python中,變量具有函數(shù)作用域,這意味著在函數(shù)內(nèi)部定義的變量不能在函數(shù)外部訪問。
作用域指的是變量的有效范圍。變量并不是在哪個位置都可以訪問的,訪問權(quán)限取決于這個變量是在哪里賦值的,也就是在哪個作用域內(nèi)的。
通常而言,在編程語言中,變量的作用域從代碼結(jié)構(gòu)形式來看,有塊級、函數(shù)、類、模塊、包等由小到大的級別。但是在Python中,沒有塊級作用域,也就是類似if語句塊、for語句塊、with上下文管理器等等是不存在作用域概念的,他們等同于普通的語句。
num = 1 def confusing_function(): num = 10 return num print(num) # 1 => Global Scope print(confusing_function()) # 10 => Local Scope
這些是Python解釋器遵循的作用域規(guī)則:
從本地開始。變量是否存在?然后獲取該值。如果沒有,請繼續(xù)
變量是否在父函數(shù)本地作用域中定義?如果存在,則獲取值,否則繼續(xù)
全局范圍內(nèi)是否存在該變量?如果存在,則獲取值,否則繼續(xù)
該變量是內(nèi)置函數(shù)嗎?獲取值否則退出
通常,函數(shù)內(nèi)部的變量無法被函數(shù)外部訪問,但內(nèi)部可以訪問;類內(nèi)部的變量無法被外部訪問,但類的內(nèi)部可以。通俗來講,就是內(nèi)部代碼可以訪問外部變量,而外部代碼通常無法訪問內(nèi)部變量。
變量的作用域決定了程序的哪一部分可以訪問哪個特定的變量名稱。Python的作用域一共有4層,分別是:
L (Local) 局部作用域
E (Enclosing) 閉包函數(shù)外的函數(shù)中
G (Global) 全局作用域
B (Built-in) 內(nèi)建作用域
x = int(2.9) # 內(nèi)建作用域,查找int函數(shù) global_var = 0 # 全局作用域 def outer(): out_var = 1 # 閉包函數(shù)外的函數(shù)中 def inner(): inner_var = 2 # 局部作用域
前面說的都是變量可以找得到的情況,那如果出現(xiàn)本身作用域沒有定義的變量,那該如何尋找呢?
Python以L –> E –> G –>B
的規(guī)則查找變量,即:在局部找不到,便會去局部外的局部找(例如閉包),再找不到就會去全局找,最后去內(nèi)建中找。如果這樣還找不到,那就提示變量不存在的錯誤。例如下面的代碼,函數(shù)func內(nèi)部并沒有定義變量a,可是print函數(shù)需要打印a,那怎么辦?向外部尋找!按照L –> E –> G –>B
的規(guī)則,層層查詢,這個例子很快就從外層查找到了a,并且知道它被賦值為1,于是就打印了1。
a = 1 def func(): print(a)
定義在函數(shù)內(nèi)部的變量擁有一個局部作用域,被叫做局部變量,定義在函數(shù)外的擁有全局作用域的變量,被稱為全局變量。(類、模塊等同理)
所謂的局部變量是相對的。局部變量也有可能是更小范圍內(nèi)的變量的外部變量。
局部變量只能在其被聲明的函數(shù)內(nèi)部訪問,而全局變量可以在整個程序范圍內(nèi)訪問。調(diào)用函數(shù)時,所有在函數(shù)內(nèi)聲明的變量名稱都將被加入到作用域中。
a = 1 # 全局變量 def func(): b = 2 # 局部變量 print(a) # 可訪問全局變量a,無法訪問它內(nèi)部的c def inner(): c = 3 # 更局部的變量 print(a) # 可以訪問全局變量a print(b) # b對于inner函數(shù)來說,就是外部變量 print(c)
我們先看下面的例子:
total = 0 # total是一個全局變量 def plus( arg1, arg2 ): total = arg1 + arg2 # total在這里是局部變量. print("函數(shù)內(nèi)局部變量total= ", total) print("函數(shù)內(nèi)的total的內(nèi)存地址是: ", id(total)) return total plus(10, 20) print("函數(shù)外部全局變量total= ", total) print("函數(shù)外的total的內(nèi)存地址是: ", id(total))
很明顯,函數(shù)plus內(nèi)部通過total = arg1 + arg2
語句,新建了一個局部變量total,它和外面的全局變量total是兩碼事。而如果我們,想要在函數(shù)內(nèi)部修改外面的全局變量total呢?使用global關(guān)鍵字!
global:指定當(dāng)前變量使用外部的全局變量
total = 0 # total是一個全局變量 def plus( arg1, arg2 ): global total # 使用global關(guān)鍵字申明此處的total引用外部的total total = arg1 + arg2 print("函數(shù)內(nèi)局部變量total= ", total) print("函數(shù)內(nèi)的total的內(nèi)存地址是: ", id(total)) return total plus(10, 20) print("函數(shù)外部全局變量total= ", total) print("函數(shù)外的total的內(nèi)存地址是: ", id(total))
打印結(jié)果是:
函數(shù)內(nèi)局部變量total= 30 函數(shù)內(nèi)的total的內(nèi)存地址是: 503494624 函數(shù)外部全局變量total= 30 函數(shù)外的total的內(nèi)存地址是: 503494624
我們再來看下面的例子:
a = 1 print("函數(shù)outer調(diào)用之前全局變量a的內(nèi)存地址: ", id(a)) def outer(): a = 2 print("函數(shù)outer調(diào)用之時閉包外部的變量a的內(nèi)存地址: ", id(a)) def inner(): a = 3 print("函數(shù)inner調(diào)用之后閉包內(nèi)部變量a的內(nèi)存地址: ", id(a)) inner() print("函數(shù)inner調(diào)用之后,閉包外部的變量a的內(nèi)存地址: ", id(a)) outer() print("函數(shù)outer執(zhí)行完畢,全局變量a的內(nèi)存地址: ", id(a))
如果你將前面的知識點(diǎn)都理解通透了,那么這里應(yīng)該沒什么問題,三個a各是各的a,各自有不同的內(nèi)存地址,是三個不同的變量。打印結(jié)果也很好的證明了這點(diǎn):
函數(shù)outer調(diào)用之前全局變量a的內(nèi)存地址: 493204544 函數(shù)outer調(diào)用之時閉包外部的變量a的內(nèi)存地址: 493204576 函數(shù)inner調(diào)用之后閉包內(nèi)部變量a的內(nèi)存地址: 493204608 函數(shù)inner調(diào)用之后,閉包外部的變量a的內(nèi)存地址: 493204576 函數(shù)outer執(zhí)行完畢,全局變量a的內(nèi)存地址: 493204544
那么,如果,inner內(nèi)部想使用outer里面的那個a,而不是全局變量的那個a,怎么辦?用global關(guān)鍵字?先試試看吧:
a = 1 print("函數(shù)outer調(diào)用之前全局變量a的內(nèi)存地址: ", id(a)) def outer(): a = 2 print("函數(shù)outer調(diào)用之時閉包外部的變量a的內(nèi)存地址: ", id(a)) def inner(): global a # 注意這行 a = 3 print("函數(shù)inner調(diào)用之后閉包內(nèi)部變量a的內(nèi)存地址: ", id(a)) inner() print("函數(shù)inner調(diào)用之后,閉包外部的變量a的內(nèi)存地址: ", id(a)) outer() print("函數(shù)outer執(zhí)行完畢,全局變量a的內(nèi)存地址: ", id(a))
運(yùn)行結(jié)果如下,很明顯,global使用的是全局變量a。
函數(shù)outer調(diào)用之前全局變量a的內(nèi)存地址: 494384192 函數(shù)outer調(diào)用之時閉包外部的變量a的內(nèi)存地址: 494384224 函數(shù)inner調(diào)用之后閉包內(nèi)部變量a的內(nèi)存地址: 494384256 函數(shù)inner調(diào)用之后,閉包外部的變量a的內(nèi)存地址: 494384224 函數(shù)outer執(zhí)行完畢,全局變量a的內(nèi)存地址: 494384256
那怎么辦呢?使用nonlocal
關(guān)鍵字!它可以修改嵌套作用域(enclosing 作用域,外層非全局作用域)中的變量。將global a
改成nonlocal a
,代碼這里我就不重復(fù)貼了,運(yùn)行后查看結(jié)果,可以看到我們真的引用了outer函數(shù)的a變量。
函數(shù)outer調(diào)用之前全局變量a的內(nèi)存地址: 497726528 函數(shù)outer調(diào)用之時閉包外部的變量a的內(nèi)存地址: 497726560 函數(shù)inner調(diào)用之后閉包內(nèi)部變量a的內(nèi)存地址: 497726592 函數(shù)inner調(diào)用之后,閉包外部的變量a的內(nèi)存地址: 497726592 函數(shù)outer執(zhí)行完畢,全局變量a的內(nèi)存地址: 497726528
關(guān)于“Python函數(shù)與參數(shù)實(shí)例代碼分析”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“Python函數(shù)與參數(shù)實(shí)例代碼分析”知識都有一定的了解,大家如果還想學(xué)習(xí)更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。