簡學Python第三章__函數式編程、遞歸、內置函數

来源:http://www.cnblogs.com/bj-xy/archive/2017/02/20/6383008.html
-Advertisement-
Play Games

Python第三章__函數式編程、遞歸、閉包 歡迎加入Linux_Python學習群 群號:478616847 目錄: 函數式編程 傳參與返回值 遞歸 匿名函數 閉包 高階函數 內置函數 函數式編程 傳參與返回值 遞歸 匿名函數 高階函數 內置函數 在第三章,我們引入新的概念函數,在以往的代碼編寫中 ...


Python第三章__函數式編程、遞歸、閉包

 

歡迎加入Linux_Python學習群

  群號:478616847

 

 

目錄:

  • 函數式編程

  • 傳參與返回值

  • 遞歸

  • 匿名函數

  • 閉包
  • 高階函數

  • 內置函數

 

在第三章,我們引入新的概念函數,在以往的代碼編寫中我們都是用的過程式編程,函數式編程的特點將過程式編程變成易於管理調用的小模塊,

讓重覆的代碼可以反覆的調用,大大減少代碼量,懶惰即美德

 

一、函數式編程

  創建函數

  一個函數式由關鍵字 def ,與函數名與括弧冒號,和括弧中的參數組成,當想要執行函數的時候只需要寫上函數名加括弧即可

  格式:  def  function (parameter)  下麵就創建一個函數

1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3 
4 #創建函數
5 def print_str():
6     print("Hello World")
7 
8 #調用函數
9 print_str()
第一個函數

  變數的作用域

  我們看一個例子,在下麵代碼中我們先把變數 a=“haha” 然後在函數中把 a=“heihei” 最後執行這個函數,並輸出變數a的結果

  我們發現為什麼a不等於 "heihei",而是我們之前賦值的 “haha” 這個現象我們馬上揭秘

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 
 5 a = "haha"
 6 
 7 #創建函數
 8 def print_str():
 9     a = "heihei"
10     print("Hello World")
11 
12 #調用函數
13 print_str()
14 print("我是變數a:",a)
變數的作用域例一

  全局變數與局部變數

  很明顯變數的作用域就是變數在哪一個範圍內生效,如果出了這個範圍則無法使用

  全局變數:通常全局變數存活在腳本運行結束,並且所有的函數都可以訪問它

  局部變數:只能局部變數所在的函數內部調用,並且除非把局部變數聲明成全局變數否則,其他函數均無法調用,並且局部變數

  當所在的函數執行完成後就不存在了

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 
 5 a = "haha"
 6 
 7 #創建函數
 8 def print_str():
 9     a = "heihei"
10     print("我是局部變數a:",a)
11 
12 
13 #調用函數
14 print_str()
15 print("我是全局變數a:",a)
全局變數與局部變數

  global

  global就是可以把局部變數變成全局變數的,如果被聲明的局部變數名與全局變數名一樣的話,那麼局部變數會覆蓋全局變數,切

  使用global聲明變數需要在變數之前聲明否則python會告訴你,你需要在 a 前面聲明

  報錯提示:SyntaxWarning: name 'a' is assigned to before global declaration global a

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 a = "haha"
 5 
 6 #創建函數
 7 def print_str():
 8     global a
 9     a = "heihei"
10     print("我是局部變數a:",a)
11 
12 #調用函數
13 print_str()
14 print("我是全局變數a:",a)
gloable

 

二、傳參與返回值

  傳參

  函數用起來比較簡單也容易理解,但是參數的變化就比較多了,在函數括弧內就是參數,參數可以接收字元串,數字,也可以接收字典和列表

  並且在調用的時候,我們還可以指定給哪個參數賦什麼值

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 #創建函數
 5 def print_str(Name,Age,Aender):
 6     print('''
 7     Name:%s
 8     Age:%s
 9     Aender:%s
10     '''%(Name,Age,Aender))
11 
12 #用戶輸入
13 in_name = input("請輸入你的名字:")
14 in_age = input("請輸入你的年齡:")
15 in_aender = input("請輸入你的性別:")
16 
17 #固定位置傳參
18 print_str(in_name,in_age,in_aender)
19 print("----------------------------------")
20 
21 #不固定位置傳參
22 print_str(in_name,Aender=in_aender,Age=in_age)
傳參

  當我們想要傳入列表或者字典時需要怎麼辦?

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 def print_str(lists):
 5     if type(lists) == list:
 6         print('''
 7         Name:%s
 8         Age:%s
 9         Aender:%s
10         '''%(lists[0],lists[1],lists[2]))
11     else:
12         print('''
13         Name:%s
14         Age:%s
15         Aender:%s
16         '''%(lists["name"],lists["age"],lists["aenber"]))
17 
18 #傳入列表
19 userlist = ["Ben","22","Man"]
20 print_str(userlist)
21 
22 print("----------------------------------")
23 #傳入字典
24 userdict = {"name":"Ben","age":"022","aender":"Man"}
25 print_str(userlist)
傳入字典或列表

  預設參數

  在函數中還可以設置預設參數,預設參數的意思是這個參數你可以傳值也可以不傳值,當不傳值的時候這個參數就等於預設值

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 def print_str(lists,Country="China"):
 5     if type(lists) == list:
 6         print('''
 7         Name:%s
 8         Age:%s
 9         Aender:%s
10         country:%s
11         '''%(lists[0],lists[1],lists[2],Country))
12     else:
13         print('''
14         Name:%s
15         Age:%s
16         Aender:%s
17         country:%s
18         '''%(lists["name"],lists["age"],lists["aenber"],Country))
19 
20 #傳入列表
21 userlist = ["Ben","22","Man"]
22 print_str(userlist)
23 
24 print("----------------------------------")
25 #傳入字典
26 userdict = {"name":"Ben","age":"022","aender":"Man"}
27 print_str(userlist,"America")
預設參數

  非固定參數

  非固定參數的意義在於可以接收任意個值,在你的函數不確定用戶想傳入多少個值的時候使用,當然在調用有隻有非固定參數的函數的時候我們可以不傳參數。

  非固定參數分一個*和兩個*,*args會把傳入的參數變成元祖,**kwargs把傳入的參數變成字典,當然*ages可以是別的名稱,但是在規範中最好使用*args,和**kwargs

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 def print_str(*args,**kwargs):
 5     print("我是*",args)
 6     print("我是**",kwargs)
 7 
 8 #傳入列表
 9 userlist = ["Ben","22","Man"]
10 print_str(userlist,"America")
11 print("----------------------------------")
12 #傳入字典
13 print_str(A = "1",B = "2")
非固定傳參

  既然形參可以帶*和**,那麼實參也是可以帶*和**,那麼*就是配合列表使用的,**就是配合字典的!

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 def print_str(*args,**kwargs):
 5     print("我是*",args)
 6     print("我是**",kwargs)
 7 
 8 #傳入列表
 9 userlist = ["Ben","22","Man"]
10 print_str(*userlist)
11 
12 print("----------------分隔符----------------")
13 
14 #傳入字典
15 userdict = {"name":"Ben","age":"022","gender":"Man"}
16 print_str(**userdict)
17 
18 解參
解參

  實參帶*就會把列表分解成   "Ben","22","Man" 一個一個單獨的元素傳入函數,而**會把字典分解成name="Ben",age="022",gender="Man"

  這種鍵值對傳入函數。

  

  形參與實參

  形參:

  變數只有在被調用時才分配記憶體單元,在調用結束時,即刻釋放所分配的記憶體單元。因此,形參只在函數內部有效。函數調用結束返回主調用

  函數後則不能再使用該形參變數

  實參:

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

  應預先用賦值,輸入等辦法使參數獲得確定值

  

  註!當普通參數和預設參數和非固定參數結合使用的時候,要遵循一個順序,普通參數在預設參數前面,預設參數在非固定參數前面

  

  返回值

  在正常使用函數的時候,函數是可以把函數內部處理的結果返回給函數調用者的,在沒有返回值得函數中會保留None傳給函數調用者,返回值可以返回序列等

  在函數執行的時候遇到return函數會停止執行,並返回結果

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 
 4 #創建函數
 5 def print_str(Age):
 6     if int(Age) <= 30:
 7         return "你才%s啊!真年輕"%(Age)
 8     else:
 9         return "你都%s啦!老家伙"%(Age)
10 
11 in_age = input("請輸入你的年齡:")
12 word = print_str(in_age)
13 print(word)
return

  

  嵌套函數

  在函數內部也可以寫函數,這樣就是外層函數套著內側函數,這種形式稱之為嵌套函數,同理因為作用域的關係嵌套函數只能內部調用

  return unction_2(stra)+"我是第二層\n" 就等於先 c = unction_2(stra) 然後 return c+"我是第二層\n"

1 def unction(stra):
2     def unction_2(stra_2):
3         return stra_2+"我是第三層\n"
4     return unction_2(stra)+"我是第二層\n"
5 
6 r_str = unction("")
7 print(r_str+"我是第一層")
嵌套函數

 

三、遞歸

  前面已經介紹了函數相關的知識,在函數中,函數可以調用其他的函數,並且函數還可以調用自身,利用這種特性我們可以完成一些特定的

  操作,這種函數調用自身的形式就是遞歸

  def recursion() :
    return recursion()

  在遞歸中不能像上面兩行一樣一直調用自身,這樣一會程式就會崩潰,因為它永遠的在調用就跟while死迴圈一樣出不去,所以遞歸也需要進

  判斷給它出口

  例子:階乘

  什麼是階乘,階乘就是給一個自然數N,然後計算N的階乘那麼 N = 1x2x3x4....N ,這個就是階乘,我們可以把它到過來看,

  N = N x (n-1) x (n-2) x (n-3) ...... 1 一直乘到括弧中的值等於1,既然知道了階乘是什麼,那麼我們來寫一個程式實現它

1 def factorial(n):
2     for i in range(1,n):
3         n *= i
4     return n
5 c = factorial(4)
6 print(c)
階乘非遞歸版本

  剖析:上面的例子首先把n=4傳入進去,然後通過 for i in range(1,4)讓i分別等於1,2,3,然後進行 n*=i,我們可以看出這個for迴圈是迴圈3次的

  第一次(n = n*i) n = 4*1 ,此時n還是等於4

  第二次(n = 4*i)  n = 4*2 此時n = 8 

  第三次(n = 8*i)  n = 8*3 此時n等於24

  此時for迴圈了3次所以結束了,通過return把n的結果返回,所以最終結果算出 4的階乘等於24

  遞歸版本

  下麵看遞歸版本的階乘

1 def factorial(n) :
2     if n == 1:
3         return 1
4     else:
5         return n * factorial(n-1)
6 c = factorial(4)
7 print(c)
階乘遞歸版本

  剖析:

  首先c = factorial(4)開始執行函數,然後進行第一次判斷 n == 1,顯然第一層n不等於1,然後碰到return n * factorial(n-1),碰到return本來是要返回的,但是 factorial(n-1)

  有調用了factiorial這個函數,因此進入了第二層

  第二層因為上一層傳入的參數是n-1,所以第二層的n是等於3的,然後判斷,這一層的n也不等於1,然後又進入第三層

  第三層n等於3,然後判斷這一層的n還不等於1,然後又進入第四層

  

  到第四層的時候這時的 n就等於1,所以觸發了 return 1 不再調用函數了,所以就開始返回

  返回第三層 return n * factorial(n-1) , 此時factorial(n-1) 就等於第四層return上去的1,所以第三層返回時就等於return n * 1(return 2 * 1),並且第三層n是等於2的

  返回第二層factorial(n-1)就等於第三層return上去的2,並且第二層n是等於3的,return 3 * 2

  返回第一層factorial(n-1)就等於第二層return上去的6,並且第一層n是等於4的,return 4 * 6

  到此為止遞歸執行完畢,c就等於 4 * 6 c=24

   

   

四、匿名函數

  匿名函數也叫lambda函數,函數沒有具體的名稱。語法:function name=  lambda  args(多個參數用逗號隔開): Expression(表達式,表達式的結果就是返回值)

  先來看一個最簡單例子:

 1 #普通函數
 2 def func(arg1,arg2):
 3     return arg1-arg2
 4 
 5 #lambda函數
 6 func_2 = lambda arg1,arg2: arg1-arg2
 7 
 8 #傳參執行
 9 print(func(5,4))
10 print(func_2(5,4))
匿名函數

  有認識,這個匿名函數和普通函數沒有什麼區別麽,其實匿名函數就像三元運算一樣,並且能夠用lambda函數有幾大優勢

  1、在一些不會再別的地方調用的函數,我們可以使用匿名函數,並且這樣簡化了代碼,看起來更加整潔。

  2、lambda函數將會搭配一些內置函數來使用(下麵會涉及到)

 

五、閉包

  在上面的示例中知道了函數可以調用函數本身,這種形式稱之為遞歸,那麼還可以將函數作為參數返回,這種形式就稱之為閉包

  閉包最大的好處就是即用即調,閉包對於安裝計算,隱藏狀態,以及在函數對象和作用域中隨意地切換是很有用的!

 1 #!/usr/bin/env python
 2 # -*- coding:utf-8 -*-
 3 def func(rate):
 4     count = [0]
 5     def add_func(arg):
 6         count[0] +=1
 7         print("第%s次調用"%count[0])
 8         arg = arg - arg*rate
 9         return arg
10     return add_func
11 
12 closure = func(0.03)
13 print(closure(1000))
14 print(closure(1100))
15 print(closure(1200))
閉包示例

  例子中做了一個減去手續費後返回餘額的功能,首先執行了func函數,將利率封裝了進去,然後,func函數把它內部的函數進行了進行了返回

  要知道當函數不加括弧的時候是不執行的!,所以此時closoure就是 add_func 函數的記憶體地址,當想要使用這個功能的時候,直接把closoure加括弧

  並傳入值即可執行。並且可以看到的是在全局作用域中執行,隨時可以切換到局部作用域。

 

六、高階函數

  函數可以用來當做返回值,可以用調用自己本身,高階函數就是函數的參數把另一個函數作為參數,這種函數就稱之為高階函數。

 1 def func_1(num):
 2     return num+1
 3 
 4 def func_2(num):
 5     return num-1
 6 
 7 def func_main(num,func):
 8     #  可以簡寫成return func(num)
 9     results = func(num)
10     return results
11 
12 results = func_main(10,func_1)
13 print(results)
14 print(func_main(10,func_2))
高階函數

  編寫高階函數,就是讓函數的參數能夠接收別的函數。

  

七、內置函數

  內置函數就是python中內置的一些方法,內置函數官方介紹請猛戳這裡

  

  內置函數使用方法示例,詳細介紹請參考

  1 # !/usr/bin/env python
  2 # -*- coding:utf-8 -*-
  3 
  4 #返回數字的絕對值。 參數可以是整數或浮點數。 如果參數是複數,則返回其大小。
  5 print(abs(-1.11))
  6 
  7 #傳入一個可被迴圈的元素,如果這個元素中有一個為False則都為假
  8 # 0 空值 False 都為假
  9 print(all([1,2,3]))
 10 
 11 #與all相反,只有一個為真,則為真;
 12 print(any([0,2,False]))
 13 
 14 #這個函數跟repr()函數一樣,返回一個可列印的對象字元串方式表示。當遇到非ASCII碼時
 15 #就會輸出\x,\u或\U等字元來表示。與Python 2版本里的repr()是等效的函數。
 16 print(ascii("dsads"),ascii(66),ascii('b\23'))
 17 
 18 #將十進位轉換為二進位;
 19 print(bin(10))
 20 
 21 #返回布爾值,即True或False之一,如果參數為false或省略,則返回False; 否則返回True。
 22 print(bool(1))
 23 
 24 #根據傳入的參數創建一個新的位元組數組
 25 #如果傳入字元串必須給出編碼
 26 print(bytearray('你好','utf-8'))
 27 #當source參數是一個可迭代對象,那麼這個對象中的元素必須符合大於0 小於256
 28 print(bytearray([256,1,2]))
 29 
 30 #返回一個的“bytes”對象,返回bytes類型
 31 bytes('中文','utf-8')
 32 
 33 #檢查對象是否可以被調用
 34 def func():
 35     pass
 36 print(callable(func))
 37 
 38 #返回整數所對應的Unicode字元,chr(97)返回字元串'a',而chr(8364)返回字元串'€'。
 39 print(chr(126))
 40 
 41 #是用來指定一個類的方法為類方法,類方法可以不實例化直接調用
 42 class A:
 43     @classmethod
 44     def B(cls,arg1,):
 45         print(arg1)
 46 A.B(1)
 47 A().B(1)
 48 
 49 #將源編譯為代碼或者AST對象。代碼對象能夠通過exec語句來執行或者eval()進行求值。
 50 #源可以是正常字元串,位元組字元串或AST對象。
 51 expr = "5+5-1"
 52 obj = compile(expr,"","eval")
 53 print(eval(obj))
 54 
 55 #返回值為real + imag * j的複數或者轉化一個字元串或數為複數。如果第一個參數為字元串,則不需要指定第二個參數。
 56 print(complex(1, 2))
 57 print(complex(1))
 58 print(complex("1+2j"))
 59 
 60 
 61 
 62 # 參數是一個對象和一個字元串。 該字元串必須是對象屬性之一的名稱。
 63 class A:
 64     def a1(self):
 65         print("a1")
 66     def a2(self):
 67         	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 今天一個兼職結束了,又要開始尋找新的兼職公司了 ,為了貼補家用啊,為了給兒子更好的生活加油! 抒情完畢進入正題,本篇文章要解決的問題是其實在開發微信支付,微信公眾號等回調地址必須是外網可訪問的80埠地址,這就導致很多開發上的不便,網上應該有很多教程做類似的了我這篇重覆造輪子一是記錄一下以備自己將來 ...
  • 數據驗證控制項 --之心 在ASP中進行表單數據驗證時,通常開發者必須自己編寫一套驗證的規則,然後自己將這些代碼拷貝到ASP代碼中對錶單進行驗證。這樣進行驗證的方式實在不太方便,幸運的是,ASP.NET解決了這個問題,這就是數據驗證Web控制項。 數據驗證控制項是ASP.NET中專門用來驗證表單用戶輸入的 ...
  • 20170220問題解析請點擊今日問題下方的“【Java每日一題】20170221”查看(問題解析在公眾號首發,公眾號ID:weknow619) 今日問題: 請問該程式運行結果是什麼?(點擊以下“【Java每日一題】20170221”查看20170220問題解析) 題目原發佈於公眾號、簡書:【Jav ...
  • 1. 一個錯誤釋放記憶體的例子 下麵的場景會有什麼錯? 一切看上去都是有序的。new匹配了一個delete。但有一些地方確實是錯了。程式的行為是未定義的。至少來說,stringArray指向的100個string對象中的99個看上去都不能被正確釋放,因為他們的析構函數可能永遠不會被調用。 2. 使用n ...
  • 本節和下節介紹線程的基本協作機制wait/notify,本節介紹協作的場景,wait/notify的基本用法和原理,以及如何實現生產者/消費者模式 ... ...
  • 轉載請標明出處: "http://www.cnblogs.com/why168888/p/6422270.html" 本文出自: "【Edwin博客園】" Python文件基礎操作(入門1) 1. python文件操作之文件打開方式 | mode | 說明 | 註意 | | | | | | 'r' ...
  • 上篇文章分享了在項目實戰中自定義Mybatis的TypeHandler來處理枚舉類型。文章結尾也指出了美中不足之處,那就是每次都需要指定我們自定義的枚舉TypeHandler。 隨著項目枚舉類型的增多,每次都要寫一遍這個會令人很反感。那麼,本次我們就來解決這一痛點。 思路分析 1. 上篇文章講到, ...
  • 註:本系列博客所使用的編程語言為Java,內容主要來自於慕課網課程:初識Java微信公眾號開發(課程鏈接:http://www.imooc.com/learn/368)的學習收穫和總結。 因為微信的大規模普及性,微信公眾號開發可以開發出跨平臺使用的功能,並且使用起來簡單方便。個人使用Java作為工作 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...