1. 程式人生 > >圖解Python 【第三篇】:Python-函數

圖解Python 【第三篇】:Python-函數

table calc 顯式 art 老男孩 idt 對象 高級 惰性

本節內容一覽圖


技術分享


一、函數介紹

1、什麽是函數

技術分享

2、定義一個函數

你可以定義一個由自己想要功能的函數,以下是簡單的規則:

    • 函數代碼塊以 def 關鍵詞開頭,後接函數標識符名稱和圓括號 ()
    • 任何傳入參數和自變量必須放在圓括號中間,圓括號之間可以用於定義參數。
    • 函數的第一行語句可以選擇性地使用文檔字符串—用於存放函數說明。
    • 函數內容以冒號起始,並且縮進。
    • return [表達式] 結束函數,選擇性地返回一個值給調用方。不帶表達式的return相當於返回 None。
    •  

註意:

    1. 函數在執行過程中只要遇到return語句,就會停止執行並返回結果,so 也可以理解為 return 語句代表著函數的結束
    2. 如果未在函數中指定return,那這個函數的返回值為None

3、函數語法:

技術分享

技術分享


二、函數參數與局部變量

一覽表:

技術分享

  

形參變量只有在被調用時才分配內存單元,在調用結束時,即刻釋放所分配的內存單元。因此,形參只在函數內部有效。函數調用結束返回主調用函數後則不能再使用該形參變量

實參可以是常量、變量、表達式、函數等,無論實參是何種類型的量,在進行函數調用時,它們都必須有確定的值,以便把這些值傳送給形參。因此應預先用賦值,輸入等辦法使參數獲得確定值

技術分享

1、默認參數

看下面代碼

1 2 3 4 5 6 7 8 9 10 def stu_register(name,age,country,course):
print("----註冊學生信息------") print("姓名:",name) print("age:",age) print("國籍:",country) print("課程:",course) stu_register("王山炮",22,"CN","python_devops") stu_register("張叫春",21,"CN","linux") stu_register("劉老根",25,"CN","linux")

發現 country 這個參數 基本都 是"CN", 就像我們在網站上註冊用戶,像國籍這種信息,你不填寫,默認就會是 中國, 這就是通過默認參數實現的,把country變成默認參數非常簡單

1 def stu_register(name,age,course,country="CN"):

這樣,這個參數在調用時不指定,那默認就是CN,指定了的話,就用你指定的值。

另外,你可能註意到了,在把country變成默認參數後,我同時把它的位置移到了最後面,為什麽呢?  

2、關鍵參數

正常情況下,給函數傳參數要按順序,不想按順序就可以用關鍵參數,只需指定參數名即可,但記住一個要求就是,關鍵參數必須放在位置參數之後。

1 stu_register(age=22,name=‘alex‘,course="python",)

  

3、非固定參數

若你的函數在定義時不確定用戶想傳入多少個參數,就可以使用非固定參數

1 2 3 4 5 6 7 8 9 10 def stu_register(name,age,*args): # *args 會把多傳入的參數變成一個元組形式 print(name,age,args) stu_register("Alex",22) #輸出 #Alex 22 () #後面這個()就是args,只是因為沒傳值,所以為空 stu_register("Jack",32,"CN","Python") #輸出 # Jack 32 (‘CN‘, ‘Python‘)

還可以有一個**kwargs

1 2 3 4 5 6 7 8 9 10 def stu_register(name,age,*args,**kwargs): # *kwargs 會把多傳入的參數變成一個dict形式 print(name,age,args,kwargs) stu_register("Alex",22) #輸出 #Alex 22 () {}#後面這個{}就是kwargs,只是因為沒傳值,所以為空 stu_register("Jack",32,"CN","Python",sex="Male",province="ShanDong") #輸出 # Jack 32 (‘CN‘, ‘Python‘) {‘province‘: ‘ShanDong‘, ‘sex‘: ‘Male‘}

4、局部變量  

1 2 3 4 5 6 7 8 9 10 11 name = "Alex Li" def change_name(name): print("before change:",name) name = "金角大王,一個有Tesla的男人" print("after change", name) change_name(name) print("在外面看看name改了麽?",name)

輸出

1 2 3 before change: Alex Li after change 金角大王,一個有Tesla的男人 在外面看看name改了麽? Alex Li

5、全局與局部變量

在子程序中定義的變量稱為局部變量,在程序的一開始定義的變量稱為全局變量。 全局變量作用域是整個程序,局部變量作用域是定義該變量的子程序。 當全局變量與局部變量同名時: 在定義局部變量的子程序內,局部變量起作用;在其它地方全局變量起作用


三、函數基礎類型

1、匿名函數

lambda表達式

技術分享
# ###################### 普通函數 ######################
# 定義函數(普通方式)
def func(arg):
    return arg + 1
    
# 執行函數
result = func(123)
    
# ###################### lambda ######################
    
# 定義函數(lambda表達式)
my_lambda = lambda arg : arg + 1
    
# 執行函數
result = my_lambda(123)
View Code

匿名函數就是不需要顯式的指定函數

技術分享
#這段代碼
def calc(n):
    return n**n
print(calc(10))
 
#換成匿名函數
calc = lambda n:n**n
print(calc(10))
View Code

匿名函數有個限制,就是只能有一個表達式,不用寫return,返回值就是該表達式的結果

技術分享
#!/usr/bin/python3
 
# 可寫函數說明
sum = lambda arg1, arg2: arg1 + arg2;
 
# 調用sum函數
print ("相加後的值為 : ", sum( 10, 20 ))
print ("相加後的值為 : ", sum( 20, 20 ))
View Code

小結

Python對匿名函數的支持有限,只有一些簡單的情況下可以使用匿名函數。

  • lambda 只是一個表達式,函數體比 def 簡單很多。
  • lambda的主體是一個表達式,而不是一個代碼塊。僅僅能在lambda表達式中封裝有限的邏輯進去。
  • lambda 函數擁有自己的命名空間,且不能訪問自己參數列表之外或全局命名空間裏的參數。
  • 雖然lambda函數看起來只能寫一行,卻不等同於C或C++的內聯函數,後者的目的是調用小函數時不占用棧內存從而增加運行效率。

2、遞歸函數

在函數內部,可以調用其他函數。如果一個函數在內部調用自身本身,這個函數就是遞歸函數

尾遞歸調用時,如果做了優化,棧不會增長,因此,無論多少次調用也不會導致棧溢出。

遺憾的是,大多數編程語言沒有針對尾遞歸做優化,Python解釋器也沒有做優化,所以,即使把上面的fact(n)函數改成尾遞歸方式,也會導致棧溢出。

小結

使用遞歸函數的優點是邏輯簡單清晰,缺點是過深的調用會導致棧溢出。

針對尾遞歸優化的語言可以通過尾遞歸防止棧溢出。尾遞歸事實上和循環是等價的,沒有循環語句的編程語言只能通過尾遞歸實現循環。

Python標準的解釋器沒有針對尾遞歸做優化,任何遞歸函數都存在棧溢出的問題。


3、裝飾器

小結

在面向對象(OOP)的設計模式中,decorator被稱為裝飾模式。OOP的裝飾模式需要通過繼承和組合來實現,而Python除了能支持OOP的decorator外,直接從語法層次支持decorator。Python的decorator可以用函數實現,也可以用類實現。

decorator可以增強函數的功能,定義起來雖然有點復雜,但使用起來非常靈活和方便


4、內置函數

技術分享  

註:查看詳細猛擊這裏


四、高級特性:

1、生成器generator

Python中,這種一邊循環一邊計算的機制,稱為生成器:generator

定義:一個函數調用時返回一個叠代器,那這個函數就叫做生成器(generator),如果函數中包含yield語法,那這個函數就會變成生成器

第一種方法很簡單,只要把一個列表生成式的[]改成(),就創建了一個generator:

通過next()函數獲得generator的下一個返回值

使用for循環,因為generator也是可叠代對象

第二種方法。如果一個函數定義中包含yield關鍵字,那麽這個函數就不再是一個普通函數,而是一個generator:

2、叠代

如果給定一個list或tuple,我們可以通過for循環來遍歷這個list或tuple,這種遍歷我們稱為叠代(Iteration)

在Python中,叠代是通過for ... in來完成的,而很多語言比如C或者Java,叠代list是通過下標完成的

任何可叠代對象都可以作用於for循環,包括我們自定義的數據類型,只要符合叠代條件,就可以使用for循環

3、叠代器Iterator

技術分享

叠代器是訪問集合元素的一種方式。

叠代器是一個可以記住遍歷的位置的對象。

叠代器對象從集合的第一個元素開始訪問,直到所有的元素被訪問完結束。叠代器只能往前不會後退。

叠代器有兩個基本的方法:iter()next()

字符串,列表或元組對象都可用於創建叠代器

可以直接作用於for循環的數據類型有以下幾種:

一類是集合數據類型,如listtupledictsetstr等;

一類是generator,包括生成器和帶yield的generator function。

這些可以直接作用於for循環的對象統稱為可叠代對象:Iterable

可以使用isinstance()判斷一個對象是否是Iterable對象:

生成器都是Iterator對象,但listdictstr雖然是Iterable,卻不是Iterator

listdictstrIterable變成Iterator可以使用iter()函數

特點:

  1. 訪問者不需要關心叠代器內部的結構,僅需通過next()方法不斷去取下一個內容
  2. 不能隨機訪問集合中的某個值 ,只能從頭到尾依次訪問
  3. 訪問到一半時不能往回退
  4. 便於循環比較大的數據集合,節省內存

小結

凡是可作用於for循環的對象都是Iterable類型;

凡是可作用於next()函數的對象都是Iterator類型,它們表示一個惰性計算的序列;

集合數據類型如listdictstr等是Iterable但不是Iterator,不過可以通過iter()函數獲得一個Iterator對象。

Python的for循環本質上就是通過不斷調用next()函數實現的


聲明:

本人在學習老男孩python自動化網絡課程後,結合所學整理做次筆記,本文內容多出

Alex老師博客:http://www.cnblogs.com/alex3714/articles/5740985.html

武沛齊老師博客:http://www.cnblogs.com/wupeiqi/articles/5453708.html

感謝老男孩教育老師Alex,武沛齊老師,本文多從二位老師文章中結合整理

感謝麻瓜編程侯爵

http://www.runoob.com/python3/python3-basic-syntax.html

https://python.xiaoleilu.com/100/101.html

http://www.ituring.com.cn/book/1863

https://www.liaoxuefeng.com/wiki/0014316089557264a6b348958f449949df42a6d3a2e542c000/0014318435599930270c0381a3b44db991cd6d858064ac0000

圖解Python 【第三篇】:Python-函數