首先你要明白,Python的函數傳遞方式是賦值,而賦值是通過建立變量與對象的關聯(lián)實現(xiàn)的。
創(chuàng)新互聯(lián)是一家集網站建設,儀隴企業(yè)網站建設,儀隴品牌網站建設,網站定制,儀隴網站建設報價,網絡營銷,網絡優(yōu)化,儀隴網站推廣為一體的創(chuàng)新建站企業(yè),幫助傳統(tǒng)企業(yè)提升企業(yè)形象加強企業(yè)競爭力??沙浞譂M足這一群體相比中小企業(yè)更為豐富、高端、多元的互聯(lián)網需求。同時我們時刻保持專業(yè)、時尚、前沿,時刻以成就客戶成長自我,堅持不斷學習、思考、沉淀、凈化自己,讓我們?yōu)楦嗟钠髽I(yè)打造出實用型網站。
對于你的代碼:
執(zhí)行 d = 2時,你在__main__里創(chuàng)建了d,并讓它指向2這個整型對象。
執(zhí)行函數add(d)過程中:
d被傳遞給add()函數后,在函數內部,num也指向了__main__中的2
但執(zhí)行num = num + 10之后,新建了對象12,并讓num指向了這個新對象——12。
如果你明白函數中的局部變量與__main__中變量的區(qū)別,那么很顯然,在__main__中,d仍在指著2這個對象,它沒有改變。因此,你打印d時得到了2。
如果你想讓輸出為12,最簡潔的辦法是:
在函數add()里增加return num
調用函數時使用d = add(d)
代碼如下:
def add(num):
num += 10
return num
d = 2
d = add(d)
print d
python 的函數參數類型分為4種:
1.位置參數:調用函數時根據函數定義的參數位置來傳遞參數,位置參數也可以叫做必要參數,函數調用時必須要傳的參數。
當參數滿足函數必要參數傳參的條件,函數能夠正常執(zhí)行:
add(1,2) #兩個參數的順序必須一一對應,且少一個參數都不可以
當我們運行上面的程序,輸出:
當函數需要兩個必要參數,但是調用函數只給了一個參數時,程序會拋出異常
add(1)
當我們運行上面的程序,輸出:
當函數需要兩個必要參數,但是調用函數只給了三個參數時,程序會拋出異常
add(1,2,3)
當我們運行上面的程序,輸出
2.關鍵字參數:用于函數調用,通過“鍵-值”形式加以指定??梢宰尯瘮蹈忧逦?、容易使用,同時也清除了參數的順序需求。
add(1,2) # 這種方式傳參,必須按順序傳參:x對應1,y對應:2
add(y=2,x=1) #以關健字方式傳入參數(可以不按順序)
正確的調用方式
add(x=1, y=2)
add(y=2, x=1)
add(1, y=2)
以上調用方式都是允許的,能夠正常執(zhí)行
錯誤的調用方式
add(x=1, 2)
add(y=2, 1)
以上調用都會拋出SyntaxError 異常
上面例子可以看出:有位置參數時,位置參數必須在關鍵字參數的前面,但關鍵字參數之間不存在先后順序的
3.默認參數:用于定義函數,為參數提供默認值,調用函數時可傳可不傳該默認參數的值,所有位置參數必須出現(xiàn)在默認參數前,包括函數定義和調用,有多個默認參數時,調用的時候,既可以按順序提供默認參數,也可以不按順序提供部分默認參數。當不按順序提供部分默認參數時,需要把參數名寫上
默認參數的函數定義
上面示例第一個是正確的定義位置參數的方式,第二個是錯誤的,因為位置參數在前,默認參數在后
def add1(x=1,y) 的定義會拋出如下異常
默認參數的函數調用
注意:定義默認參數默認參數最好不要定義為可變對象,容易掉坑
不可變對象:該對象所指向的內存中的值不能被改變,int,string,float,tuple
可變對象,該對象所指向的內存中的值可以被改變,dict,list
這里只要理解一下這個概念就行或者自行百度,后續(xù)會寫相關的專題文章講解
舉一個簡單示例
4.可變參數區(qū)別:定義函數時,有時候我們不確定調用的時候會多少個參數,j就可以使用可變參數
可變參數主要有兩類:
*args: (positional argument) 允許任意數量的可選位置參數(參數),將被分配給一個元組, 參數名前帶*,args只是約定俗成的變量名,可以替換其他名稱
**kwargs:(keyword argument) 允許任意數量的可選關鍵字參數,,將被分配給一個字典,參數名前帶**,kwargs只是約定俗成的變量名,可以替換其他名稱
*args 的用法
args 是用來傳遞一個非鍵值對的可變數量的參數列表給函數
語法是使用 符號的數量可變的參數; 按照慣例,通常是使用arg這個單詞,args相當于一個變量名,可以自己定義的
在上面的程序中,我們使用* args作為一個可變長度參數列表傳遞給add()函數。 在函數中,我們有一個循環(huán)實現(xiàn)傳遞的參數計算和輸出結果。
還可以直接傳遞列表或者數組的方式傳遞參數,以數組或者列表方式傳遞參數名前面加(*) 號
理解* * kwargs
**kwargs 允許你將不定長度的鍵值對, 作為參數傳遞給函數,這些關鍵字參數在函數內部自動組裝為一個dict
下篇詳細講解 *args, **kwargs 的參數傳遞和使用敬請關注
對于可變參數默認是引用傳值, 但是不能去修改它的指向, 一旦修改就是按值傳遞.
#?coding=utf-8
def?f(a):
a?=?[0]
print(a)
if?__name__?==?'__main__':
a?=?[1,?2,?3]
f(a)
print(a)
上面的代碼對a重新賦值, 試圖改變a的指向, 那么這時的a就是一個新的局部變量, 而非全局變量a
像a[0] = 100, a.append(0)的操作不會觸發(fā)上述規(guī)則, 和你的輸出一樣
函數參數傳遞機制問題在本質上是調用函數(過程)和被調用函數(過程)在調用發(fā)生時進行通信的方法問題?;镜膮祩鬟f機制有兩
種:值傳遞和引用傳遞。
推薦:Python教程
值傳遞(passl-by-value)過程中,被調函數的形式參數作為被調函數的局部變量處理,即在堆棧中開辟了內存空間以存放由主調函數放
進來的實參的值,從而成為了實參的一個副本。值傳遞的特點是被調函數對形式參數的任何操作都是作為局部變量進行,不會影響主調函
數的實參變量的值。
引用傳遞(pass-by-reference)過程中,被調函數的形式參數雖然也作為局部變量在堆棧中開辟了內存空間,但是這時存放的是由主調函
數放進來的實參變量的地址。被調函數對形參的任何操作都被處理成間接尋址,即通過堆棧中存放的地址訪問主調函數中的實參變量。正
因為如此,被調函數對形參做的任何操作都影響了主調函數中的實參變量。
更多技術請關注Python視頻教程。
有
b.傳參方式
i:位置傳參
就是在不知名傳參參數名的情況下直接利用參數的索引來進行傳參,如上個栗子
ii:關鍵字傳參
與位置傳參相對,直接利用參數名進行傳參,如下:
對象vs變量
在python中,類型屬于對象,變量是沒有類型的,這正是python的語言特性,也是吸引著很多pythoner的一點。所有的變量都可以理解是內存中一個對象的“引用”,或者,也可以看似c中void*的感覺。所以,希望大家在看到一個python變量的時候,把變量和真正的內存對象分開。
類型是屬于對象的,而不是變量。
這樣,很多問題就容易思考了。
例如:
對象vs變量
12
nfoo = 1 #一個指向int數據類型的nfoo(再次提醒,nfoo沒有類型)lstFoo = [1] #一個指向list類型的lstFoo,這個list中包含一個整數1
可更改(mutable)與不可更改(immutable)對象
對應于上一個概念,就必須引出另了另一概念,這就是可更改(mutable)對象與不可更改(immutable)對象。
對于python比較熟悉的人們都應該了解這個事實,在python中,strings, tuples, 和numbers是不可更改的對象,而list,dict等則是可以修改的對象。那么,這些所謂的可改變和不可改變影響著什么呢?
可更改vs不可更改
12345
nfoo = 1nfoo = 2lstFoo = [1]lstFoo[0] = 2
代碼第2行中,內存中原始的1對象因為不能改變,于是被“拋棄”,另nfoo指向一個新的int對象,其值為2
代碼第5行中,更改list中第一個元素的值,因為list是可改變的,所以,第一個元素變更為2。其實應該說,lstFoo指向一個包含一個對象的數組。賦值所發(fā)生的事情,是有一個新int對象被指定給lstFoo所指向的數組對象的第一個元素,但是對于lstFoo本身來說,所指向的數組對象并沒有變化,只是數組對象的內容發(fā)生變化了。這個看似void*的變量所指向的對象仍舊是剛剛的那個有一個int對象的list。
如下圖所示:
Python的函數參數傳遞:傳值?引用?
對于變量(與對象相對的概念),其實,python函數參數傳遞可以理解為就是變量傳值操作,用C++的方式理解,就是對void*賦值。如果這個變量的值不變,我們看似就是引用,如果這個變量的值改變,我們看著像是在賦值。有點暈是吧,我們仍舊據個例子。
不可變對象參數調用
12345
def ChangeInt( a ): a = 10nfoo = 2 ChangeInt(nfoo)print nfoo #結果是2
這時發(fā)生了什么,有一個int對象2,和指向它的變量nfoo,當傳遞給ChangeInt的時候,按照傳值的方式,復制了變量nfoo的值,這樣,a就是nfoo指向同一個Int對象了,函數中a=10的時候,發(fā)生什么?(還記得我上面講到的那些概念么),int是不能更改的對象,于是,做了一個新的int對象,另a指向它(但是此時,被變量nfoo指向的對象,沒有發(fā)生變化),于是在外面的感覺就是函數沒有改變nfoo的值,看起來像C++中的傳值方式。
可變對象參數調用
12345
def ChangeList( a ): a[0] = 10lstFoo = [2]ChangeList(lstFoo )print nfoo #結果是[10]
當傳遞給ChangeList的時候,變量仍舊按照“傳值”的方式,復制了變量lstFoo 的值,于是a和lstFoo 指向同一個對象,但是,list是可以改變的對象,對a[0]的操作,就是對lstFoo指向的對象的內容的操作,于是,這時的a[0] = 10,就是更改了lstFoo 指向的對象的第一個元素,所以,再次輸出lstFoo 時,顯示[10],內容被改變了,看起來,像C++中的按引用傳遞。