python的函數(shù)參數(shù)傳遞是"引用傳遞(地址傳遞)"。
在成都做網(wǎng)站、成都網(wǎng)站建設(shè)、成都外貿(mào)網(wǎng)站建設(shè)過程中,需要針對(duì)客戶的行業(yè)特點(diǎn)、產(chǎn)品特性、目標(biāo)受眾和市場(chǎng)情況進(jìn)行定位分析,以確定網(wǎng)站的風(fēng)格、色彩、版式、交互等方面的設(shè)計(jì)方向。成都創(chuàng)新互聯(lián)還需要根據(jù)客戶的需求進(jìn)行功能模塊的開發(fā)和設(shè)計(jì),包括內(nèi)容管理、前臺(tái)展示、用戶權(quán)限管理、數(shù)據(jù)統(tǒng)計(jì)和安全保護(hù)等功能。
python中賦值語(yǔ)句的過程(x = 1):先申請(qǐng)一段內(nèi)存分配給一個(gè)整型對(duì)象來存儲(chǔ)數(shù)據(jù)1,然后讓變量x去指向這個(gè)對(duì)象,實(shí)際上就是指向這段內(nèi)存(這里有點(diǎn)和C語(yǔ)言中的指針類似)。
在Python中,會(huì)為每個(gè)層次生成一個(gè)符號(hào)表,里層能調(diào)用外層中的變量,而外層不能調(diào)用里層中的變量,并且當(dāng)外層和里層有同名變量時(shí),外層變量會(huì)被里層變量屏蔽掉。函數(shù)? 調(diào)用 ?會(huì)為函數(shù)局部變量生成一個(gè)新的符號(hào)表。
局部變量:作用于該函數(shù)內(nèi)部,一旦函數(shù)執(zhí)行完成,該變量就被回收。
全局變量:它是在函數(shù)外部定義的,作用域是整個(gè)文件。全局變量可以直接在函數(shù)里面應(yīng)用,但是如果要在函數(shù)內(nèi)部改變?nèi)肿兞浚仨毷褂胓lobal關(guān)鍵字進(jìn)行聲明。
注意 :默認(rèn)值在函數(shù)? 定義 ?作用域被解析
在定義函數(shù)時(shí),就已經(jīng)執(zhí)行力它的局部變量
python中不可變類型是共享內(nèi)存地址的:把相同的兩個(gè)不可變類型數(shù)據(jù)賦給兩個(gè)不同變量a,b,a,b在內(nèi)存中的地址是一樣的。
函數(shù)參數(shù)傳遞機(jī)制問題在本質(zhì)上是調(diào)用函數(shù)(過程)和被調(diào)用函數(shù)(過程)在調(diào)用發(fā)生時(shí)進(jìn)行通信的方法問題。基本的參數(shù)傳遞機(jī)制有兩
種:值傳遞和引用傳遞。
推薦:Python教程
值傳遞(passl-by-value)過程中,被調(diào)函數(shù)的形式參數(shù)作為被調(diào)函數(shù)的局部變量處理,即在堆棧中開辟了內(nèi)存空間以存放由主調(diào)函數(shù)放
進(jìn)來的實(shí)參的值,從而成為了實(shí)參的一個(gè)副本。值傳遞的特點(diǎn)是被調(diào)函數(shù)對(duì)形式參數(shù)的任何操作都是作為局部變量進(jìn)行,不會(huì)影響主調(diào)函
數(shù)的實(shí)參變量的值。
引用傳遞(pass-by-reference)過程中,被調(diào)函數(shù)的形式參數(shù)雖然也作為局部變量在堆棧中開辟了內(nèi)存空間,但是這時(shí)存放的是由主調(diào)函
數(shù)放進(jìn)來的實(shí)參變量的地址。被調(diào)函數(shù)對(duì)形參的任何操作都被處理成間接尋址,即通過堆棧中存放的地址訪問主調(diào)函數(shù)中的實(shí)參變量。正
因?yàn)槿绱?,被調(diào)函數(shù)對(duì)形參做的任何操作都影響了主調(diào)函數(shù)中的實(shí)參變量。
更多技術(shù)請(qǐng)關(guān)注Python視頻教程。
Python 函數(shù)定義以及參數(shù)傳遞
1.函數(shù)定義
#形如def func(args...):
doSomething123
以關(guān)鍵字def 開頭,后面是函數(shù)名和參數(shù)下面是函數(shù)處理過程。
舉例:
def add( a, b ):
return a+b12
參數(shù)可以設(shè)定默認(rèn)值,如:
def add( a, b=10 ): #注意:默認(rèn)值參數(shù)只會(huì)運(yùn)算一次
return a+b12
默認(rèn)值參數(shù)只會(huì)運(yùn)算一次是什么意思?
def func( a, b=[] ): #b的默認(rèn)值指向一個(gè)空的列表,每次不帶默認(rèn)值都會(huì)指向這塊內(nèi)存
b.append(a) return b
print(func(1))#向默認(rèn)的空列表里加入元素1 ,默認(rèn)列表里已經(jīng)是[1]print(func(2))#向默認(rèn)的列表里加入元素2,默認(rèn)列表里已經(jīng)是[1,2]print(func(3,[]))#向b指向的空列表里加入元素1 ,默認(rèn)列表里還是[1,2]print(func(4))#向默認(rèn)的列表里加入元素4,默認(rèn)列表里已經(jīng)是[1,2,4]'''
結(jié)果:
[1]
[1, 2]
[3]
[1, 2, 4]
'''12345678910111213141516
這下明白為什么默認(rèn)參數(shù)只計(jì)算一次了吧,函數(shù)參數(shù)不傳遞時(shí)默認(rèn)值總是指向固定的內(nèi)存空間,就是第一次計(jì)算的空間。
2.參數(shù)傳遞
def func(a, b):
print('a=%d, b=%d' % (a,b) )12
在使用函數(shù)時(shí)可以如下方式,結(jié)果都是相同的
func(10,20) #不使用參數(shù)名,需要按參數(shù)順序傳遞func(a=10,b=20) #使用參數(shù)名可以不按順序傳遞func(b=20,a=10)#結(jié)果:a=10, b=20a=10, b=20a=10, b=201234567
如果函數(shù)定義形式如下方式:
def func(*args): #這種定義會(huì)把傳遞的參數(shù)包成元組
print(args,type(args))
func(10,20)#結(jié)果:#(10, 20) class 'tuple'1234567
舉一個(gè)和上述過程相反的例子:
def func(a,b):
print('a=%d, b=%d' % (a,b) )
a = (10, 20)
func(*a) #在調(diào)用函數(shù)使用`*`則會(huì)把元組解包成單個(gè)變量按順序傳入函數(shù)#結(jié)果:a=10, b=20123456
總結(jié):*號(hào)在定義函數(shù)參數(shù)時(shí),傳入函數(shù)的參數(shù)會(huì)轉(zhuǎn)換成元組,如果 *號(hào)在調(diào)用時(shí)則會(huì)把元組解包成單個(gè)元素。
另一種定義:
def func(**kw):#使用**定義參數(shù)會(huì)把傳入?yún)?shù)包裝成字典dict
print(kw, type(kw) )
func(a=10,b=20)#這種函數(shù)在使用時(shí)必須指定參數(shù)值,使用key=value這種形式#結(jié)果:{'b': 20, 'a': 10} class 'dict'12345
相反的例子:
def func(a,b):
print('a=%d, b=%d' % (a,b) )
d = {'a':10, 'b':20 }
func(**d) #在調(diào)用時(shí)使用**會(huì)把字典解包成變量傳入函數(shù)。12345
def func(*args, **kw):#這種形式的定義代表可以接受任意類型的參數(shù)
print(args,kw )12
總結(jié):**號(hào)在定義函數(shù)參數(shù)時(shí),傳入函數(shù)的參數(shù)會(huì)轉(zhuǎn)換成字典,如果 **號(hào)在調(diào)用時(shí)則會(huì)把字典解包成單個(gè)元素。
lambda表達(dá)式
lambda表達(dá)式就是一種簡(jiǎn)單的函數(shù)
形如 f = lambda 參數(shù)1,參數(shù)2: 返回的計(jì)算值
例如:
add = lambda x,y: x+y
print(add(1,2))'''
結(jié)果:3
'''12345
對(duì)象vs變量
在python中,類型屬于對(duì)象,變量是沒有類型的,這正是python的語(yǔ)言特性,也是吸引著很多pythoner的一點(diǎn)。所有的變量都可以理解是內(nèi)存中一個(gè)對(duì)象的“引用”,或者,也可以看似c中void*的感覺。所以,希望大家在看到一個(gè)python變量的時(shí)候,把變量和真正的內(nèi)存對(duì)象分開。
類型是屬于對(duì)象的,而不是變量。
這樣,很多問題就容易思考了。
例如:
對(duì)象vs變量
12
nfoo = 1 #一個(gè)指向int數(shù)據(jù)類型的nfoo(再次提醒,nfoo沒有類型)lstFoo = [1] #一個(gè)指向list類型的lstFoo,這個(gè)list中包含一個(gè)整數(shù)1
可更改(mutable)與不可更改(immutable)對(duì)象
對(duì)應(yīng)于上一個(gè)概念,就必須引出另了另一概念,這就是可更改(mutable)對(duì)象與不可更改(immutable)對(duì)象。
對(duì)于python比較熟悉的人們都應(yīng)該了解這個(gè)事實(shí),在python中,strings, tuples, 和numbers是不可更改的對(duì)象,而list,dict等則是可以修改的對(duì)象。那么,這些所謂的可改變和不可改變影響著什么呢?
可更改vs不可更改
12345
nfoo = 1nfoo = 2lstFoo = [1]lstFoo[0] = 2
代碼第2行中,內(nèi)存中原始的1對(duì)象因?yàn)椴荒芨淖儯谑潜弧皰仐墶?,另nfoo指向一個(gè)新的int對(duì)象,其值為2
代碼第5行中,更改list中第一個(gè)元素的值,因?yàn)閘ist是可改變的,所以,第一個(gè)元素變更為2。其實(shí)應(yīng)該說,lstFoo指向一個(gè)包含一個(gè)對(duì)象的數(shù)組。賦值所發(fā)生的事情,是有一個(gè)新int對(duì)象被指定給lstFoo所指向的數(shù)組對(duì)象的第一個(gè)元素,但是對(duì)于lstFoo本身來說,所指向的數(shù)組對(duì)象并沒有變化,只是數(shù)組對(duì)象的內(nèi)容發(fā)生變化了。這個(gè)看似void*的變量所指向的對(duì)象仍舊是剛剛的那個(gè)有一個(gè)int對(duì)象的list。
如下圖所示:
Python的函數(shù)參數(shù)傳遞:傳值?引用?
對(duì)于變量(與對(duì)象相對(duì)的概念),其實(shí),python函數(shù)參數(shù)傳遞可以理解為就是變量傳值操作,用C++的方式理解,就是對(duì)void*賦值。如果這個(gè)變量的值不變,我們看似就是引用,如果這個(gè)變量的值改變,我們看著像是在賦值。有點(diǎn)暈是吧,我們?nèi)耘f據(jù)個(gè)例子。
不可變對(duì)象參數(shù)調(diào)用
12345
def ChangeInt( a ): a = 10nfoo = 2 ChangeInt(nfoo)print nfoo #結(jié)果是2
這時(shí)發(fā)生了什么,有一個(gè)int對(duì)象2,和指向它的變量nfoo,當(dāng)傳遞給ChangeInt的時(shí)候,按照傳值的方式,復(fù)制了變量nfoo的值,這樣,a就是nfoo指向同一個(gè)Int對(duì)象了,函數(shù)中a=10的時(shí)候,發(fā)生什么?(還記得我上面講到的那些概念么),int是不能更改的對(duì)象,于是,做了一個(gè)新的int對(duì)象,另a指向它(但是此時(shí),被變量nfoo指向的對(duì)象,沒有發(fā)生變化),于是在外面的感覺就是函數(shù)沒有改變nfoo的值,看起來像C++中的傳值方式。
可變對(duì)象參數(shù)調(diào)用
12345
def ChangeList( a ): a[0] = 10lstFoo = [2]ChangeList(lstFoo )print nfoo #結(jié)果是[10]
當(dāng)傳遞給ChangeList的時(shí)候,變量仍舊按照“傳值”的方式,復(fù)制了變量lstFoo 的值,于是a和lstFoo 指向同一個(gè)對(duì)象,但是,list是可以改變的對(duì)象,對(duì)a[0]的操作,就是對(duì)lstFoo指向的對(duì)象的內(nèi)容的操作,于是,這時(shí)的a[0] = 10,就是更改了lstFoo 指向的對(duì)象的第一個(gè)元素,所以,再次輸出lstFoo 時(shí),顯示[10],內(nèi)容被改變了,看起來,像C++中的按引用傳遞。
Python賦值操作或函數(shù)參數(shù)傳遞,傳遞的永遠(yuǎn)是對(duì)象引用(即內(nèi)存地址),而不是對(duì)象內(nèi)容。在Python中一切皆對(duì)象,對(duì)象又分為可變(mutable)和不可變(immutable)兩種類型。對(duì)象拷貝是指在內(nèi)存中創(chuàng)建新的對(duì)象,產(chǎn)生新的內(nèi)存地址。當(dāng)頂層對(duì)象和它的子元素對(duì)象全都是immutable不可變對(duì)象時(shí),不存在被拷貝,因?yàn)闆]有產(chǎn)生新對(duì)象。淺拷貝(Shallow Copy),拷貝頂層對(duì)象,但不會(huì)拷貝內(nèi)部的子元素對(duì)象。深拷貝(Deep Copy),遞歸拷貝頂層對(duì)象,以及它內(nèi)部的子元素對(duì)象。
Python中一切皆對(duì)象,對(duì)象就像一個(gè)塑料盒子, 里面裝的是數(shù)據(jù)。對(duì)象有不同類型,例如布爾型和整型,類型決定了可以對(duì)它進(jìn)行的操作。現(xiàn)實(shí)生活中的"陶器"會(huì)暗含一些信息(例如它可能很重且易碎,注意不要掉到地上)。
對(duì)象的類型還決定了它裝著的數(shù)據(jù)是允許被修改的變量(可變的mutable)還是不可被修改的常量(不可變的immutable)。你可以把不可變對(duì)象想象成一個(gè)透明但封閉的盒子:你可以看到里面裝的數(shù)據(jù),但是無(wú)法改變它。類似地,可變對(duì)象就像一個(gè)開著口的盒子,你不僅可以看到里面的數(shù)據(jù),還可以拿出來修改它,但你無(wú)法改變這個(gè)盒子本身,即你無(wú)法改變對(duì)象的類型。
對(duì)象拷貝是指在內(nèi)存中創(chuàng)建新的對(duì)象,產(chǎn)生新的內(nèi)存地址。
淺拷貝(Shallow Copy),拷貝頂層對(duì)象,但不會(huì)拷貝內(nèi)部的子元素對(duì)象。
2.1.1. 頂層是mutable,子元素全是immutable
當(dāng)頂層對(duì)象是mutable可變對(duì)象,但是它的子元素對(duì)象全都是immutable不可變對(duì)象時(shí),如[1, 'world', 2]
① 創(chuàng)建列表對(duì)象并賦值給變量a
② 導(dǎo)入copy模塊,使用copy.copy()函數(shù)淺拷貝a,并賦值給變量b
③ 修改變量a的子元素a[0] = 3,由于整數(shù)是不可變對(duì)象,所以并不是修改1變?yōu)?,而是更改a[0]指向?qū)ο?
當(dāng)頂層對(duì)象是 mutable可變對(duì)象 ,但子元素也存在 mutable可變對(duì)象 時(shí),如 [1, 2, ['hello','world']]
① 淺拷貝 copy.copy() 只拷貝了頂層對(duì)象,沒有拷貝子元素對(duì)象['hello','world'],即a[2]和b[2]指向同一個(gè)列表對(duì)象
② 修改a[2][1] = 'china',則b[2][1] = 'china'
當(dāng)頂層對(duì)象是immutable不可變對(duì)象,同時(shí)它的子元素對(duì)象也全都是immutable不可變對(duì)象時(shí),如(1, 2, 3)
變量a與變量b指向的是同一個(gè)元組對(duì)象,沒有拷貝
當(dāng)頂層對(duì)象是immutable不可變對(duì)象時(shí),但子元素存在mutable可變對(duì)象時(shí),如(1, 2, ['hello','world'])
變量a與變量b指向的是相同的元組對(duì)象,并且a[2]與b[2]指向同一個(gè)列表,所以修改a[2][1]會(huì)影響b[2][1]
深拷貝(Deep Copy),遞歸拷貝頂層對(duì)象,以及它內(nèi)部的子元素對(duì)象
當(dāng)頂層對(duì)象是mutable可變對(duì)象,但是它的子元素對(duì)象全都是immutable不可變對(duì)象時(shí),如[1, 'world', 2]
變量a與變量b指向不同的列表對(duì)象,修改a[0]只是將列表a的第一個(gè)元素重新指向新對(duì)象,不會(huì)影響b[0]
當(dāng)頂層對(duì)象是mutable可變對(duì)象,但子元素也存在mutable可變對(duì)象時(shí),如[1, 2, ['hello','world']]
深拷貝既拷貝了頂層對(duì)象,又遞歸拷貝了子元素對(duì)象,所以a[2]與b[2]指向了兩個(gè)不同的列表對(duì)象(但是列表對(duì)象的子元素初始指定的字符串對(duì)象一樣),修改a[2][1] = 'china'后,它重新指向了新的字符串對(duì)象(內(nèi)存地址為140531581905808),不會(huì)影響到b[2][1]
當(dāng)頂層對(duì)象是immutable不可變對(duì)象,同時(shí)它的子元素對(duì)象也全都是immutable不可變對(duì)象時(shí),如(1, 2, 3)
變量a與變量b指向的是同一個(gè)元組對(duì)象,不存在拷貝
當(dāng)頂層對(duì)象是immutable不可變對(duì)象時(shí),但子元素存在mutable可變對(duì)象時(shí),如(1, 2, ['hello','world'])
變量a與變量b指向的是不同的元組對(duì)象,同時(shí)a[2]與b[2]指向不同的列表對(duì)象,所以修改a[2][1]不會(huì)影響b[2][1]
使用=是賦值,即將列表對(duì)象的引用也賦值給變量b,可以將列表對(duì)象想像成一個(gè)盒子,變量a相當(dāng)于這個(gè)盒子上的標(biāo)簽,執(zhí)行b = a后,相當(dāng)于再在這個(gè)盒子上貼上b標(biāo)簽,a和b實(shí)際上指向的是同一個(gè)對(duì)象。因此,無(wú)論我們是通過a還是通過b來修改列表的內(nèi)容,其結(jié)果都會(huì)作用于雙方。
b/c/d都是a的復(fù)制,它們都指向了不同的列表對(duì)象,但是沒有拷貝子元素,a[2]和b[2]/c[2]/d[2]指向同一個(gè)列表, 相當(dāng)于淺拷貝的效果
使用分片[:]操作,a和b其實(shí)是指向同一個(gè)元組,而且沒有拷貝子元素,a[2]和b[2]也指向同一個(gè)列表,相當(dāng)于淺拷貝的效果
同列表類似,可以使用字典的copy()函數(shù)或者轉(zhuǎn)換函數(shù)dict()
變量a與變量b/c指向不同的字典,但是沒有拷貝子元素,a['jobs']和b['jobs']/c['jobs']指定同一個(gè)列表, 相當(dāng)于淺拷貝的效果
同列表類似,可以使用集合的copy()函數(shù)或者轉(zhuǎn)換函數(shù)set()
變量a與變量b/c指向不同的集合,而集合的元素必須是hashable,所以修改集合a不會(huì)影響到b/c