寫在之前
函數是很有深度的,需要我們深入探究,實踐過程中,有很多對函數的不同理解,需要我們在學習的過程中不斷的思考,下面我們在昨天文章(零基礎學習 Python 之與函數的初次相見)的基礎上,再學習一些函數的相關應用。
返回值
所謂的返回值,就是在調用函數的地方由函數返回的數據。下面我們用我們最熟悉的斐波那契數列為例,我們編寫一個函數來實現斐波那契數列:
>>> deffibs(n):... res = [0,1]... for i in range(n-2):... res.append(res[-2] + res[-1])... return res... >>> if __name__ == "__main__":... now = fibs(10)... print(now)...
在上面的代碼中我們首先定義了一個函數,名字叫做 fibs,參數是輸入一個整數(其實你輸入非整數也是可以的,只是結果不同),然後通過 now = fibs(10) 調用這個函數。這裡的參數給的是 10,這就以為著要得到的是 n = 10 的斐波那契數列。運行以後的結果如下 :
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
當然如果你想換 n 的值,只需要在調用的時候修改一下參數就好了。然後我們來觀察上面的函數,最後有一個語句 return res,意思是將 res 的值返回,但是返回給誰呢?這要看是在什麼位置調用的函數。在上面的代碼中,用 now = fibs(10) 調用了函數,那麼函數就將值返回到當前狀態,並記錄在內存中,然後把它賦值給變量 now。
需要注意的,上面雖然返回的是列表,但其實只是返回了一個返回值,有時候我們需要返回多個的時候,要用元組的方式。
>>> defmy_digit():... return1,2,3... >>> now = my_digit()>>> now(1, 2, 3)
對於上面的這個函數,其實我們還可以像下面一樣:
>>> x,y,z = my_digit()>>> x1>>> y2>>> z3
並不是所以的函數都有 return,比如某些函數就只是執行一條語句或者乾脆什麼也不做,它們不需要返回值,其實看過昨天文章的朋友可能會有印象,其實它們也有,只不過是 None。比如下面的函數:
>>> defcau():... pass... >>> now = cau()>>> print(now)None
這個函數的作用就是什麼也不做,當然也就不需要 return。
我們可以特別注意一下那個 return,它其實還有一個作用,請看下面的例子:
>>> defmy_info():... print('my name is rocky')... return... print('i like python')... >>> my_info()my name is rocky
看出什麼了嗎?明明有兩個 print,在中間插入一個 return 以後,只執行了第一個 print,第二個並沒有執行。這是因為在第一個之後遇到 return,它告訴函數要終端函數體內的流程,所以 return 在這裡的作用就是:結束正在執行的流程,並離開函數體返回到調用的位置。
函數的文檔
函數的文檔,一般是寫在函數的名字下面,說明這個函數的用途,因為這個我感覺很重要,之前雖然也說過注釋的重要性,但還是感覺有必要再次說明。
deffibs(n):"""這是一個求斐波那契數列的函數 """
在函數的下面,用三對引號的方式包裹著這個函數文檔,也叫函數的說明。
比如我們用 dir 來查看函數對象,比如 dir(type),我們會看到 __doc__,這個就是文檔:
>>> dir(type)['__abstractmethods__', '__base__', '__bases__', '__basicsize__', '__call__', '__class__', '__delattr__', '__dict__', '__dictoffset__', '__dir__', '__doc__', '__eq__', '__flags__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__instancecheck__', '__itemsize__', '__le__', '__lt__', '__module__', '__mro__', '__name__', '__ne__', '__new__', '__prepare__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasscheck__', '__subclasses__', '__subclasshook__', '__text_signature__', '__weakrefoffset__', 'mro']>>> type.__doc__"type(object_or_name, bases, dict)\ntype(object) -> the object's type\ntype(name, bases, dict) -> a new type"
如果上面的例子在交互模式下的話,用 help(fibs),得到的也是三對引號所包裹的文檔信息,感興趣的可以嘗試一下。
函數的屬性
任何對象都具有屬性,我們前面的文章說過函數是對象,那麼函數也有屬性。
>>> defcau():... """this is a cau function"""... pass...
對於上面的函數,最熟悉的屬性應該就是上面提到的函數文檔 __doc__,它可以用英文句號的方式表示為 cau.__doc__:
>>> cau.__doc__'this is a cau function'
這就能體現出這種方式表示函數屬性的優勢,只要對象不同,不管你屬性的名字是否相同,用英文句號都可以說明屬性所對應的對象。
我們還可以給對象增加屬性,比如我們給 cau 增加一個 pig 屬性,並設置為 100,順便我們再調用一下它:
>>> cau.pig = 100>>> cau.pig100
還記得上面我說的那個查看對象屬性和方法的 dir 嗎?現在有請它閃亮登場:
>>> dir(cau)['__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'pig']
在這裡列出了所有 cau 這個函數對象的屬性和方法,仔細觀察我們會發現,我們剛用過的 __doc__ 和我們新增加的 pig 都在其中,至於你在糾結那些名字前後都是用雙下劃線的,你暫且可以把它們稱之為特殊屬性,所有的這些屬性都是可以用英文句點的方式調用,感興趣的可以試一試。
寫在之後
本來在這裡想把參數和變量一起說了,但是基於現在的篇幅長度和參數變量那涉及的東西,一起寫的話顯得太長了。其實在我的認知裡,從公眾號上學知識其實不是最好的方式,因為代碼什麼的看起來不舒服,所以文章的內容在你有限的耐心時間段裡看能達到相比來所比較好的效果。
最近比較忙,我現在還在堅持著每天更新,我儘量擠出時間來寫文章,可能不能做的那麼盡善盡美,希望朋友們能理解。
最後感謝你能看到這裡,希望我寫的東西能夠讓你有到收穫,每天收穫一點點,持之以恆,水能穿石。
The end。
看我這麼賣力還不專注一波