函數(shù),對于人類來講,能夠發(fā)展到這個數(shù)學思維層次,是一個飛躍。可以說,它的提出,直接加快了現(xiàn)代科技和社會的發(fā)展,不論是現(xiàn)代的任何科技門類,乃至于經(jīng)濟學、政治學、社會學等,都已經(jīng)普遍使用函數(shù)。
下面一段來自維基百科(在本教程中,大量的定義來自維基百科,因為它真的很百科):函數(shù)詞條
函數(shù)這個數(shù)學名詞是萊布尼茲在 1694 年開始使用的,以描述曲線的一個相關量,如曲線的斜率或者曲線上的某一點。萊布尼茲所指的函數(shù)現(xiàn)在被稱作可導函數(shù),數(shù)學家之外的普通人一般接觸到的函數(shù)即屬此類。對于可導函數(shù)可以討論它的極限和導數(shù)。此兩者描述了函數(shù)輸出值的變化同輸入值變化的關系,是微積分學的基礎。
中文的“函數(shù)”一詞由清朝數(shù)學家李善蘭譯出。其《代數(shù)學》書中解釋:“凡此變數(shù)中函(包含)彼變數(shù)者,則此為彼之函數(shù)”。
函數(shù),從簡單到復雜,各式各樣。前面提供的維基百科中的函數(shù)詞條,里面可以做一個概覽。但不管什么樣子的函數(shù),都可以用下圖概括:
http://wiki.jikexueyuan.com/project/start-learning-python/images/20101.png" alt="" />
有初中數(shù)學水平都能理解一個大概了。這里不贅述。
本講重點說明用 Python 怎么來構造一個函數(shù)。
在中學數(shù)學中,可以用這樣的方式定義函數(shù):y=4x+3,這就是一個一次函數(shù),當然,也可以寫成:f(x)=4x+3。其中 x 是變量,它可以代表任何數(shù)。
當 x=2 時,代入到上面的函數(shù)表達式:
f(2) = 4*2+3 = 11
所以:f(2) = 11
但是,這并不是函數(shù)的全部,在函數(shù)中,其實變量并沒有規(guī)定只能是一個數(shù),它可以是饅頭、還可是蘋果,不知道讀者是否對函數(shù)有這個層次的理解。請繼續(xù)閱讀即更深刻
變量 x 只能是任意數(shù)嗎?其實,一個函數(shù),就是一個對應關系??垂賴L試著將上面表達式的 x 理解為餡餅,4x+3,就是 4 個餡餅在加上 3(一般來講,單位是統(tǒng)一的,但你非讓它不統(tǒng)一,也無妨),這個結果對應著另外一個東西,那個東西比如說是 iphone?;蛘哒f可以理解為 4 個餡餅加 3 就對應一個 iphone。這就是所謂映射關系。
所以,x,不僅僅是數(shù),可以是你認為的任何東西。
函數(shù)中為什么變量用 x?這是一個有趣的問題,自己 google 一下,看能不能找到答案。
我也不清楚原因。不過,我清楚地知道,變量可以用 x,也可以用別的符號,比如 y,z,k,i,j...,甚至用 alpha,beta 這樣的字母組合也可以。
變量在本質上就是一個占位符。這是一針見血的理解。什么是占位符?就是先把那個位置用變量占上,表示這里有一個東西,至于這個位置放什么東西,以后再說,反正先用一個符號占著這個位置(占位符)。
其實在高級語言編程中,變量比我們在初中數(shù)學中學習的要復雜。但是,先不管那些,復雜東西放在以后再說了?,F(xiàn)在,就按照初中數(shù)學來研究 Python 中的變量。
通常使小寫字母來命名 Python 中的變量,也可以在其中加上下劃線什么的,表示區(qū)別。
比如:alpha,x,j,p_beta,這些都可以做為 Python 的變量。
>>> a = 2
>>> y=3*a+2
>>> y
8
這種方式建立的函數(shù),跟在初中數(shù)學中學習的沒有什么區(qū)別。當然,這種方式的函數(shù),在編程實踐中的用途不大,一般是在學習階段理解函數(shù)來使用的。
別急躁,你在輸入 a=3,然后輸入 y,看看得到什么結果呢?
>>> a=2
>>> y=3*a+2
>>> y
8
>>> a=3
>>> y
8
是不是很奇怪?為什么后面已經(jīng)讓a等于3了,結果 y 還是 8。
還記得前面已經(jīng)學習過的關于“變量賦值”的原理嗎?a=2
的含義是將 2 這個對象貼上了變量 a 標簽,經(jīng)過計算,得到了 8,之后變量 y 引用了對象 8。當變量 a 引用的對象修改為3的時候,但是y引用的對象還沒有變,所以,還是 8。再計算一次,y 的連接對象就變了:
>>> a=3
>>> y
8
>>> y=3*a+2
>>> y
11
特別注意,如果沒有先 a=2,就直接下函數(shù)表達式了,像這樣,就會報錯。
>>> y=3*a+2
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'a' is not defined
注意看錯誤提示,a 是一個變量,提示中告訴我們這個變量沒有定義。顯然,如果函數(shù)中要使用某個變量,不得不提前定義出來。定義方法就是給這個變量賦值。
上面用命令方式建立函數(shù),還不夠“正規(guī)化”,那么就來寫一個.py 文件吧。
例如下面的代碼:
#!/usr/bin/env python
#coding:utf-8
def add_function(a,b):
c = a + b
print c
if __name__ == "__main__":
add_function(2,3)
然后將文件保存,我把她命名為 20101.py,你根據(jù)自己的喜好取個名字。
然后我就進入到那個文件夾,運行這個文件,出現(xiàn)下面的結果,如圖:
http://wiki.jikexueyuan.com/project/start-learning-python/images/20102.png" alt="" />
你運行的結果是什么?如果沒有得到上面的結果,你就非常認真地檢查代碼,是否跟我寫的完全一樣,注意,包括冒號和空格,都得一樣。冒號和空格很重要。
下面開始庖丁解牛:
def add_function(a,b)
: 這里是函數(shù)的開始。在聲明要建立一個函數(shù)的時候,一定要使用 def(def 就是英文 define 的前三個字母),意思就是告知計算機,這里要聲明一個函數(shù);add_function 是這個函數(shù)名稱,取名字是有講究的,就好比你的名字一樣。在 Python 中取名字的講究就是要有一定意義,能夠從名字中看出這個函數(shù)是用來干什么的。從 add_function 這個名字中,是不是看出她是用來計算加法的呢(嚴格地說,是把兩個對象“相加”,這里相加的含義是比較寬泛的,包括對字符串等相加)?(a,b)這個括號里面的是這個函數(shù)的參數(shù),也就是函數(shù)變量。冒號,這個冒號非常非常重要,如果少了,就報錯了。冒號的意思就是下面好開始真正的函數(shù)內(nèi)容了。c=a+b
特別注意,這一行比上一行要縮進四個空格。這是 Python 的規(guī)定,要牢記,不可丟掉,丟了就報錯。然后這句話就是將兩個參數(shù)(變量)相加,結果賦值與另外一個變量 c。print c
還是提醒看官注意,縮進四個空格。將得到的結果 c 的值打印出來。if __name__=="__main__"
: 這句話先照抄,不解釋,因為在《自省》有說明,不知道你是不是認真閱讀了。注意就是不縮進了。解牛完畢,做個總結:
定義函數(shù)的格式為:
def 函數(shù)名(參數(shù) 1,參數(shù) 2,...,參數(shù) n):
函數(shù)體(語句塊)
是不是樣式很簡單呢?
幾點說明:
看簡單例子,深入理解上面的要點:
>>> def name(): #定義一個無參數(shù)的函數(shù),只是通過這個函數(shù)打印
... print "qiwsir" #縮進 4 個空格
...
>>> name() #調用函數(shù),打印結果
qiwsir
>>> def add(x,y): #定義一個非常簡單的函數(shù)
... return x+y #縮進 4 個空格
...
>>> add(2,3) #通過函數(shù),計算 2+3
5
注意上面的 add(x,y)函數(shù),在這個函數(shù)中,沒有特別規(guī)定參數(shù) x,y 的類型。其實,這句話本身就是錯的,還記得在前面已經(jīng)多次提到,在 Python 中,變量無類型,只有對象才有類型,這句話應該說成:x,y 并沒有嚴格規(guī)定其所引用的對象類型。這是 Python 跟某些語言比如 java 很大的區(qū)別,在有些語言中,需要在定義函數(shù)的時候告訴函數(shù)參數(shù)的數(shù)據(jù)類型。Python 不用那樣做。
為什么?列位不要忘記了,這里的所謂參數(shù),跟前面說的變量,本質上是一回事。只有當用到該變量的時候,才建立變量與對象的對應關系,否則,關系不建立。而對象才有類型。那么,在 add(x,y) 函數(shù)中,x,y 在引用對象之前,是完全飄忽的,沒有被貼在任何一個對象上,換句話說它們有可能引用任何對象,只要后面的運算許可,如果后面的運算不許可,則會報錯。
>>> add("qiw","sir") #這里,x="qiw",y="sir",讓函數(shù)計算 x+y,也就是"qiw"+"sir"
'qiwsir'
>>> add("qiwsir",4)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in add
TypeError: cannot concatenate 'str' and 'int' objects #仔細閱讀報錯信息,就明白錯誤之處了
從實驗結果中發(fā)現(xiàn):x+y 的意義完全取決于對象的類型。在 Python 中,將這種依賴關系,稱之為多態(tài)。對于 Python 中的多態(tài)問題,以后還會遇到,這里僅僅以此例子顯示一番。請看官要留心注意的:Python 中為對象編寫接口,而不是為數(shù)據(jù)類型。讀者先留心一下這句話,或者記住它,隨著學習的深入,會領悟到其真諦的。
此外,也可以將函數(shù)通過賦值語句,與某個變量建立引用關系:
>>> result = add(3,4)
>>> result
7
在這里,其實解釋了函數(shù)的一個秘密。add(x,y) 在被運行之前,計算機內(nèi)是不存在的,直到代碼運行到這里的時候,在計算機中,就建立起來了一個對象,這就如同前面所學習過的字符串、列表等類型的對象一樣,運行 add(x,y) 之后,也建立了一個 add(x,y) 的對象,這個對象與變量 result 可以建立引用關系,并且 add(x,y) 將運算結果返回。于是,通過 result 就可以查看運算結果。
如果看官上面一段,感覺有點吃力或者暈乎,也不要緊,那就再讀一邊。是在搞不明白,就不要搞了。隨著學習的深入,它會被明白的。
到現(xiàn)在為止,我們已經(jīng)接觸過變量的命名、函數(shù)的命名問題。似乎已經(jīng)到了將命名問題進行總結的時候了。
在某國,向來重視“名”,所謂“名不正言不順”,取名字或者給什么東西命名,常常是天大的事情,在很多時候就是為了那個“名”進行爭斗。
江湖上還有的大師,會通過某個人的名字來預測他/她的吉兇禍福等??磥砻诌@玩意太重要了?!懊徽圆豁槨?,歪解:名字不正規(guī)化,就不順。這是歪解,希望不要影響看官正確理解。不知道大師們是不是能夠通過外國人名字預測外國人大的吉兇禍福呢?
不管怎樣,某國人是很在意名字的,旁邊有個國家似乎就不在乎。
Python 也很在乎名字問題,其實,所有高級語言對名字都有要求。為什么呢?因為如果命名亂了,計算機就有點不知所措了???Python 對命名的一般要求。
文件名:全小寫,可使用下劃線
函數(shù)名:小寫,可以用下劃線風格單詞以增加可讀性。如:myfunction,my_example_function。注意:混合大小寫僅被允許用于這種風格已經(jīng)占據(jù)優(yōu)勢的時候,以便保持向后兼容。有的人,喜歡用這樣的命名風格:myFunction,除了第一個單詞首字母外,后面的單詞首字母大寫。這也是可以的,因為在某些語言中就習慣如此。
函數(shù)的參數(shù):如果一個函數(shù)的參數(shù)名稱和保留的關鍵字(所謂保留關鍵字,就是 Python 語言已經(jīng)占用的名稱,通常被用來做為已經(jīng)有的函數(shù)等的命名了,你如果還用,就不行了。)沖突,通常使用一個后綴下劃線好于使用縮寫或奇怪的拼寫。
其實,關于命名的問題,還有不少爭論呢?最典型的是所謂匈牙利命名法、駝峰命名等。如果你喜歡,可以 google 一下。以下內(nèi)容供參考:
前面的例子中已經(jīng)有了一些關于調用的問題,為了深入理解,把這個問題單獨拿出來看看。
為什么要寫函數(shù)?從理論上說,不用函數(shù),也能夠編程,我們在前面已經(jīng)寫了程序,就沒有寫函數(shù),當然,用 Python 的內(nèi)建函數(shù)姑且不算了?,F(xiàn)在之所以使用函數(shù),主要是:
這樣看來,函數(shù)還是很必要的了。廢話少說,那就看函數(shù)怎么調用吧。以 add(x,y) 為例,前面已經(jīng)演示了基本調用方式,此外,還可以這樣:
>>> def add(x,y): #為了能夠更明了顯示參數(shù)賦值特點,重寫此函數(shù)
... print "x=",x #分別打印參數(shù)賦值結果
... print "y=",y
... return x+y
...
>>> add(10,3) #x=10,y=3
x= 10
y= 3
13
>>> add(3,10) #x=3,y=10
x= 3
y= 10
13
所謂調用,最關鍵是要弄清楚如何給函數(shù)的參數(shù)賦值。這里就是按照參數(shù)次序賦值,根據(jù)參數(shù)的位置,值與之對應。
>>> add(x=10,y=3) #同上
x= 10
y= 3
13
還可以直接把賦值語句寫到里面,就明確了參數(shù)和對象的關系。當然,這時候順序就不重要了,也可以這樣
>>> add(y=10,x=3) #x=3,y=10
x= 3
y= 10
13
在定義函數(shù)的時候,參數(shù)可以像前面那樣,等待被賦值,也可以定義的時候就賦給一個默認值。例如:
>>> def times(x,y=2): #y的默認值為 2
... print "x=",x
... print "y=",y
... return x*y
...
>>> times(3) #x=3,y=2
x= 3
y= 2
6
>>> times(x=3) #同上
x= 3
y= 2
6
如果不給那個有默認值的參數(shù)傳遞值(賦值的另外一種說法),那么它就是用默認的值。如果給它傳一個,它就采用新賦給它的值。如下:
>>> times(3,4) #x=3,y=4,y 的值不再是 2
x= 3
y= 4
12
>>> times("qiwsir") #再次體現(xiàn)了多態(tài)特點
x= qiwsir
y= 2
'qiwsirqiwsir'
給列位看官提一個思考題,請在閑暇之余用 Python 完成:寫兩個數(shù)的加、減、乘、除的函數(shù),然后用這些函數(shù),完成簡單的計算。
下面的若干條,是常見編寫代碼的注意事項:
以上各點如果有不理解的,也不要緊,在以后編程中,是不是地回來復習一下,能不斷領悟其內(nèi)涵。
總目錄 | 上節(jié):自省 | 下節(jié):函數(shù)(2)
如果你認為有必要打賞我,請通過支付寶:qiwsir@126.com,不勝感激。