99re热视频这里只精品,久久久天堂国产精品女人,国产av一区二区三区,久久久精品成人免费看片,99久久精品免费看国产一区二区三区

函數(shù)(2)

2018-02-24 15:48 更新

在上一節(jié)中,已經(jīng)明確了函數(shù)的基本結(jié)構(gòu)和初步的調(diào)用方法。但是,上一節(jié)中寫(xiě)的函數(shù),還有點(diǎn)缺憾,不知道讀者是否覺(jué)察到了。我把結(jié)果是用print語(yǔ)句打印出來(lái)的。這是實(shí)際編程中廣泛使用的嗎?肯定不是。因?yàn)楹瘮?shù)在編程中,起到一段具有抽象價(jià)值的代碼作用,一般情況下,用它得到一個(gè)結(jié)果,這個(gè)結(jié)果要用在其它的運(yùn)算中。所以,不能僅僅局限在把某個(gè)結(jié)果打印出來(lái)。所以,函數(shù)必須返回一個(gè)結(jié)果。

結(jié)論:函數(shù)要有返回值,也必須有返回值。

返回值

為了能夠說(shuō)明清楚,先編寫(xiě)一個(gè)函數(shù)。還記得斐波那契數(shù)列嗎?我打算定義一個(gè)能夠得到斐波那契數(shù)列的函數(shù),從而實(shí)現(xiàn)可以實(shí)現(xiàn)任意的數(shù)列。你先想想,要怎么寫(xiě)?

參考代碼:

#!/usr/bin/env python
# coding=utf-8

def fibs(n):
    result = [0,1]
    for i in range(n-2):
        result.append(result[-2] + result[-1])
    return result

if __name__ == "__main__":
    lst = fibs(10)
    print lst

把含有這些代碼的文件保存為名為20202.py的文件。在這個(gè)文件中,首先定義了一個(gè)函數(shù),名字叫做fibs,其參數(shù)是輸入一個(gè)整數(shù)。在后面,通過(guò)lst = fibs(10)調(diào)用這個(gè)函數(shù)。這里參數(shù)給的是10,就意味著要得到n=10的斐波那契數(shù)列。

運(yùn)行后打印數(shù)列:

$ python 20202.py
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]

當(dāng)然,如果要換n的值,只需要在調(diào)用函數(shù)的時(shí)候,修改一下參數(shù)即可。這才體現(xiàn)出函數(shù)的優(yōu)勢(shì)呢。

觀察fibs函數(shù),最后有一個(gè)語(yǔ)句return result,意思是將變量result的值返回。返回給誰(shuí)呢?一般這類函數(shù)調(diào)用的時(shí)候,要通過(guò)類似lst = fibs(10)的語(yǔ)句,那么返回的那個(gè)值,就被變量lst貼上了,通過(guò)lst就能得到該值。如果沒(méi)有這個(gè)賦值語(yǔ)句,雖然函數(shù)照樣返回值,但是它飄忽在內(nèi)存中,我們無(wú)法得到,并且最終還被當(dāng)做垃圾被python回收了。

注意:上面的函數(shù)之返回了一個(gè)返回值(是一個(gè)列表),有時(shí)候需要返回多個(gè),是以元組形式返回。

>>> def my_fun():
...     return 1,2,3
... 
>>> a = my_fun()
>>> a
(1, 2, 3)

有的函數(shù),沒(méi)有renturn,一樣執(zhí)行完畢,就算也干了某些活兒吧。事實(shí)上,不是沒(méi)有返回值,也有,只不過(guò)是None。比如這樣一個(gè)函數(shù):

>>> def my_fun():
...     print "I am doing somthin."
... 

我在交互模式下構(gòu)造一個(gè)很簡(jiǎn)單的函數(shù),注意,我這是構(gòu)造了一個(gè)簡(jiǎn)單函數(shù),如果是復(fù)雜的,千萬(wàn)不要在交互模式下做。如果你非要做,是能?chē)L到苦頭的。

這個(gè)函數(shù)的作用就是打印出一段話。也就是執(zhí)行這個(gè)函數(shù),就能打印出那段話,但是沒(méi)有return。

>>> a = my_fun()
I am doing somthin.

我們?cè)倏纯茨莻€(gè)變量a,到底是什么

>>> print a
None

這就是這類只干活兒,沒(méi)有return的函數(shù),返回給變量的是一個(gè)None。這種模樣的函數(shù),通常不用上述方式調(diào)用,而采用下面的方式,因?yàn)樗麄兎祷氐氖荖one,似乎這個(gè)返回值利用價(jià)值不高,于是就不用找一個(gè)變量來(lái)接受返回值了。

>>> my_fun()
I am doing somthin.

特別注意那個(gè)return,它還有一個(gè)作用。觀察下面的函數(shù)和執(zhí)行結(jié)果,看看能不能發(fā)現(xiàn)它的另外一個(gè)作用。

>>> def my_fun():
...     print "I am coding."
...     return
...     print "I finished."
... 
>>> my_fun()
I am coding.

看出玄機(jī)了嗎?在函數(shù)中,本來(lái)有兩個(gè)print語(yǔ)句,但是中間插入了一個(gè)return,僅僅是一個(gè)return。當(dāng)執(zhí)行函數(shù)的時(shí)候,只執(zhí)行了第一個(gè)print語(yǔ)句,第二個(gè)并沒(méi)有執(zhí)行。這是因?yàn)榈谝粋€(gè)之后,遇到了return,它告訴函數(shù)要返回,即中斷函數(shù)體內(nèi)的流程,離開(kāi)這個(gè)函數(shù)。結(jié)果第二個(gè)print就沒(méi)有被執(zhí)行。所以,return在這里就有了一個(gè)作用,結(jié)束正在執(zhí)行的函數(shù)。有點(diǎn)類似循環(huán)中的break的作用。

函數(shù)中的文檔

“程序在大多數(shù)情況下是給人看的,只是偶爾被機(jī)器執(zhí)行以下。”所以,寫(xiě)程序必須要寫(xiě)注釋。前面已經(jīng)有過(guò)說(shuō)明,如果用#開(kāi)始,python就不執(zhí)行那句(python看不到它,但是人能看到),它就作為注釋存在。

除了這樣的一句之外,一般在每個(gè)函數(shù)名字的下面,還要寫(xiě)一寫(xiě)文檔,以此來(lái)說(shuō)明這個(gè)函數(shù)的用途。

#!/usr/bin/env python
# coding=utf-8

def fibs(n):
    """
    This is a Fibonacci sequence.
    """
    result = [0,1]
    for i in range(n-2):
        result.append(result[-2] + result[-1])
    return result

if __name__ == "__main__":
    lst = fibs(10)
    print lst

在這個(gè)函數(shù)的名稱下面,用三個(gè)引號(hào)的方式,包裹著對(duì)這個(gè)函數(shù)的說(shuō)明,那個(gè)就是函數(shù)文檔。

還記得在《自省》那節(jié)中,提到的__doc__嗎?對(duì)于函數(shù),它的內(nèi)容就來(lái)自這里。

>>> def my_fun():
...     """
...     This is my function.
...     """
...     print "I am a craft."
... 
>>> my_fun.__doc__
'\n    This is my function.\n    '

如果在交互模式中用help(my_fun)得到的也是三個(gè)引號(hào)所包裹的文檔信息。

Help on function my_fun in module __main__:

my_fun()
    This is my function.

參數(shù)和變量

參數(shù)

雖然在上一節(jié),已經(jīng)知道如何通過(guò)函數(shù)的參數(shù)傳值,如何調(diào)用函數(shù)等。但是,這里還有必要進(jìn)一步討論參數(shù)問(wèn)題。在別的程序員嘴里,你或許聽(tīng)說(shuō)過(guò)“形參”、“實(shí)參”、“參數(shù)”等名詞,到底指什么呢?

在定義函數(shù)的時(shí)候(def來(lái)定義函數(shù),稱為def語(yǔ)句),函數(shù)名后面的括號(hào)里如果有變量,它們通常被稱為“形參”。調(diào)用函數(shù)的時(shí)候,給函數(shù)提供的值叫做“實(shí)參”,或者“參數(shù)”。

其實(shí),根本不用區(qū)分這個(gè),因?yàn)闆](méi)有什么意義,只不過(guò)類似孔乙己先生知道茴香豆的茴字有多少種寫(xiě)法罷了。但是,我居然碰到過(guò)某公司面試官問(wèn)這種問(wèn)題。

在本教程中,把那個(gè)所謂實(shí)參,就稱之為值(或者數(shù)據(jù)、或者對(duì)象),形參就籠統(tǒng)稱之為參數(shù)(似乎不很合理,但是接近數(shù)學(xué)概念)。

比較參數(shù)和變量

參數(shù)問(wèn)題就算說(shuō)明白了,糊涂就糊涂吧,也沒(méi)有什么關(guān)系。不過(guò),對(duì)于變量和參數(shù),這兩個(gè)就不能算糊涂賬了。因?yàn)樗菀鬃屓撕苛恕?/p>

在數(shù)學(xué)的函數(shù)中y = 3x + 2,那個(gè)x叫做參數(shù),也可以叫做變量。但是,在編程語(yǔ)言的函數(shù)中,與此有異。

先參考一段來(lái)自微軟網(wǎng)站的比較高度抽象,而且意義涵蓋深遠(yuǎn)的說(shuō)明。我摘抄過(guò)來(lái),看官讀一讀,是否理解,雖然是針對(duì)VB而言的,一樣有啟發(fā)。

參數(shù)和變量之間的差異 (Visual Basic)

多數(shù)情況下,過(guò)程必須包含有關(guān)調(diào)用環(huán)境的一些信息。執(zhí)行重復(fù)或共享任務(wù)的過(guò)程對(duì)每次調(diào)用使用不同的信息。此信息包含每次調(diào)用過(guò)程時(shí)傳遞給它的變量、常量和表達(dá)式。

若要將此信息傳遞給過(guò)程,過(guò)程先要定義一個(gè)形參,然后調(diào)用代碼將一個(gè)實(shí)參傳遞給所定義的形參。 您可以將形參當(dāng)作一個(gè)停車(chē)位,而將實(shí)參當(dāng)作一輛汽車(chē)。 就像一個(gè)停車(chē)位可以在不同時(shí)間停放不同的汽車(chē)一樣,調(diào)用代碼在每次調(diào)用過(guò)程時(shí)可以將不同的實(shí)參傳遞給同一個(gè)形參。

形參表示一個(gè)值,過(guò)程希望您在調(diào)用它時(shí)傳遞該值。

當(dāng)您定義 Function 或 Sub 過(guò)程時(shí),需要在緊跟過(guò)程名稱的括號(hào)內(nèi)指定形參列表。對(duì)于每個(gè)形參,您可以指定名稱、數(shù)據(jù)類型和傳入機(jī)制(ByVal (Visual Basic) 或 ByRef (Visual Basic))。您還可以指示某個(gè)形參是可選的。這意味著調(diào)用代碼不必傳遞它的值。

每個(gè)形參的名稱均可作為過(guò)程內(nèi)的局部變量。形參名稱的使用方法與其他任何變量的使用方法相同。

實(shí)參表示在您調(diào)用過(guò)程時(shí)傳遞給過(guò)程形參的值。調(diào)用代碼在調(diào)用過(guò)程時(shí)提供參數(shù)。

調(diào)用 Function 或 Sub 過(guò)程時(shí),需要在緊跟過(guò)程名稱的括號(hào)內(nèi)包括實(shí)參列表。每個(gè)實(shí)參均與此列表中位于相同位置的那個(gè)形參相對(duì)應(yīng)。

與形參定義不同,實(shí)參沒(méi)有名稱。每個(gè)實(shí)參就是一個(gè)表達(dá)式,它包含零或多個(gè)變量、常數(shù)和文本。求值的表達(dá)式的數(shù)據(jù)類型通常應(yīng)與為相應(yīng)形參定義的數(shù)據(jù)類型相匹配,并且在任何情況下,該表達(dá)式值都必須可轉(zhuǎn)換為此形參類型。

看官如果硬著頭皮看完這段引文,發(fā)現(xiàn)里面有幾個(gè)關(guān)鍵詞:參數(shù)、變量、形參、實(shí)參。本來(lái)想弄清楚參數(shù)和變量,結(jié)果又冒出另外兩個(gè)東東,更混亂了。請(qǐng)稍安勿躁,本來(lái)這段引文就是有點(diǎn)多余,但是,之所以引用,就是讓列位開(kāi)闊一下眼界,在編程業(yè)界,類似的東西有很多名詞。下次聽(tīng)到有人說(shuō)這些,不用害怕啦,反正自己聽(tīng)過(guò)了。

在Python中,沒(méi)有這么復(fù)雜。

看完上面讓人暈頭轉(zhuǎn)向的引文之后,再看下面的代碼,就會(huì)豁然開(kāi)朗了。

>>> def add(x):     #x是參數(shù),準(zhǔn)確說(shuō)是形參
...     a = 10      #a是變量
...     return a+x  #x就是那個(gè)形參作為變量,其本質(zhì)是要傳遞賦給這個(gè)函數(shù)的值
... 
>>> x = 3           #x是變量,只不過(guò)在函數(shù)之外
>>> add(x)          #這里的x是參數(shù),但是它由前面的變量x傳遞對(duì)象3
13
>>> add(3)          #把上面的過(guò)程合并了
13

至此,看官是否清楚了一點(diǎn)點(diǎn)。當(dāng)然,我所表述不正確之處或者理解錯(cuò)誤之處,也請(qǐng)看官不吝賜教,小可作揖感謝。

其實(shí)沒(méi)有那么復(fù)雜。關(guān)鍵要理解函數(shù)名括號(hào)后面的東東(管它什么參呢)的作用是傳遞值。

全局變量和局部變量

下面是一段代碼,注意這段代碼中有一個(gè)函數(shù)funcx(),這個(gè)函數(shù)里面有一個(gè)變量x=9,在函數(shù)的前面也有一個(gè)變量x=2

x = 2

def funcx():
    x = 9
    print "this x is in the funcx:-->",x

funcx()
print "--------------------------"
print "this x is out of funcx:-->",x

那么,這段代碼輸出的結(jié)果是什么呢?看:

this x is in the funcx:--> 9
--------------------------
this x is out of funcx:--> 2

從輸出看出,運(yùn)行funcx(),輸出了funcx()里面的變量x=9;然后執(zhí)行代碼中的最后一行,print "this x is out of funcx:-->",x

特別要關(guān)注的是,前一個(gè)x輸出的是函數(shù)內(nèi)部的變量x;后一個(gè)x輸出的是函數(shù)外面的變量x。兩個(gè)變量彼此沒(méi)有互相影響,雖然都是x。從這里看出,兩個(gè)x各自在各自的領(lǐng)域內(nèi)起到作用。

把那個(gè)只在函數(shù)體內(nèi)(某個(gè)范圍內(nèi))起作用的變量稱之為局部變量。

有局部,就有對(duì)應(yīng)的全部,在漢語(yǔ)中,全部變量,似乎有歧義,幸虧漢語(yǔ)豐富,于是又取了一個(gè)名詞:全局變量

x = 2
def funcx():
    global x    #跟上面函數(shù)的不同之處
    x = 9
    print "this x is in the funcx:-->",x

funcx()
print "--------------------------"
print "this x is out of funcx:-->",x

以上兩段代碼的不同之處在于,后者在函數(shù)內(nèi)多了一個(gè)global x,這句話的意思是在聲明x是全局變量,也就是說(shuō)這個(gè)x跟函數(shù)外面的那個(gè)x同一個(gè),接下來(lái)通過(guò)x=9將x的引用對(duì)象變成了9。所以,就出現(xiàn)了下面的結(jié)果。

this x is in the funcx:--> 9
--------------------------
this x is out of funcx:--> 9

好似全局變量能力很強(qiáng)悍,能夠統(tǒng)帥函數(shù)內(nèi)外。但是,要注意,這個(gè)東西要慎重使用,因?yàn)橥菀讕?lái)變量的換亂。內(nèi)外有別,在程序中一定要注意的。

命名空間

這是一個(gè)比較不容易理解的概念,特別是對(duì)于初學(xué)者而言,似乎它很飄渺。我在維基百科中看到對(duì)它的定義,不僅定義比較好,連里面的例子都不錯(cuò)。所以,抄錄下來(lái),幫助讀者理解這個(gè)名詞。

命名空間(英語(yǔ):Namespace)表示標(biāo)識(shí)符(identifier)的可見(jiàn)范圍。一個(gè)標(biāo)識(shí)符可在多個(gè)命名空間中定義,它在不同命名空間中的含義是互不相干的。這樣,在一個(gè)新的命名空間中可定義任何標(biāo)識(shí)符,它們不會(huì)與任何已有的標(biāo)識(shí)符發(fā)生沖突,因?yàn)橐延械亩x都處于其它命名空間中。

例如,設(shè)Bill是X公司的員工,工號(hào)為123,而John是Y公司的員工,工號(hào)也是123。由于兩人在不同的公司工作,可以使用相同的工號(hào)來(lái)標(biāo)識(shí)而不會(huì)造成混亂,這里每個(gè)公司就表示一個(gè)獨(dú)立的命名空間。如果兩人在同一家公司工作,其工號(hào)就不能相同了,否則在支付工資時(shí)便會(huì)發(fā)生混亂。

這一特點(diǎn)是使用命名空間的主要理由。在大型的計(jì)算機(jī)程序或文檔中,往往會(huì)出現(xiàn)數(shù)百或數(shù)千個(gè)標(biāo)識(shí)符。命名空間(或類似的方法,見(jiàn)“命名空間的模擬”一節(jié))提供一隱藏區(qū)域標(biāo)識(shí)符的機(jī)制。通過(guò)將邏輯上相關(guān)的標(biāo)識(shí)符組織成相應(yīng)的命名空間,可使整個(gè)系統(tǒng)更加模塊化。

在編程語(yǔ)言中,命名空間是對(duì)作用域的一種特殊的抽象,它包含了處于該作用域內(nèi)的標(biāo)識(shí)符,且本身也用一個(gè)標(biāo)識(shí)符來(lái)表示,這樣便將一系列在邏輯上相關(guān)的標(biāo)識(shí)符用一個(gè)標(biāo)識(shí)符組織了起來(lái)。許多現(xiàn)代編程語(yǔ)言都支持命名空間。在一些編程語(yǔ)言(例如C++和Python)中,命名空間本身的標(biāo)識(shí)符也屬于一個(gè)外層的命名空間,也即命名空間可以嵌套,構(gòu)成一個(gè)命名空間樹(shù),樹(shù)根則是無(wú)名的全局命名空間。

函數(shù)和類的作用域可被視作隱式命名空間,它們和可見(jiàn)性、可訪問(wèn)性和對(duì)象生命周期不可分割的聯(lián)系在一起。

顯然,用“命名空間”或者“作用域”這樣的名詞,就是因?yàn)橛辛撕瘮?shù)(后面還會(huì)有類)之后,在函數(shù)內(nèi)外都可能有外形一樣的符號(hào)(標(biāo)識(shí)符),在python中(乃至于其它高級(jí)語(yǔ)言),通常就是變量,為了區(qū)分此變量非彼變量(雖然外形一樣),需要用這樣的東西來(lái)框定每個(gè)變量所對(duì)應(yīng)的值(發(fā)生作用的范圍)。

前面已經(jīng)講過(guò),變量和對(duì)象(就是所變量所對(duì)應(yīng)的值)之間的關(guān)系是:變量類似標(biāo)簽,貼在了對(duì)象上。也就是,通過(guò)賦值語(yǔ)句實(shí)現(xiàn)了一個(gè)變量標(biāo)簽對(duì)應(yīng)一個(gè)數(shù)據(jù)對(duì)象(值),這種對(duì)應(yīng)關(guān)系讓你想起了什么?映射!python中唯一的映射就是dict,里面有“鍵值對(duì)”。變量和值得關(guān)系就有點(diǎn)像“鍵”和“值”的關(guān)系。有一個(gè)內(nèi)建函數(shù)vars,可以幫助我們研究一下這種對(duì)應(yīng)關(guān)系。

>>> x = 7
>>> scope = vars()
>>> scope['x']
7
>>> scope['x'] += 1
>>> x
8
>>> scope['x']
8

既然如此,誠(chéng)如前面的全局變量和局部變量,即使是同樣一個(gè)變量名稱。但是它在不同范圍(還是用“命名空間”這個(gè)詞是不是更專業(yè)呢?)對(duì)應(yīng)不同的值。

以上內(nèi)容是否對(duì)您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號(hào)
微信公眾號(hào)

編程獅公眾號(hào)