小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

從C#到Python -- 3 函數(shù)及其編程

 無名小卒917 2014-11-11

在C#中沒有獨(dú)立的函數(shù)存在,只有類的(動態(tài)或靜態(tài))方法這一概念,它指的是類中用于執(zhí)行計算或其它行為的成員。在Python中,你可以使用類似C#的方式定義類的動態(tài)或靜態(tài)成員方法,因為它與C#一樣支持完全的面向?qū)ο缶幊?。你也可以用過程式編程的方式來編寫Python程序,這時Python中的函數(shù)與類可以沒有任何關(guān)系,類似C語言定義和使用函數(shù)的方式。此外,Python還支持函數(shù)式編程,雖然它對函數(shù)式編程的支持不如LISP等語言那樣完備,但適當(dāng)使用還是可以提高我們工作的效率。

本章主要介紹在過程編程模式下Python中函數(shù)的定義和使用方法,關(guān)于在面向?qū)ο缶幊讨腥绾问褂煤瘮?shù),我們將在下一章再討論。此外,我還會簡要介紹Python中的函數(shù)編程功能。

3.1  函數(shù)的定義

函數(shù)定義是最基本的行為抽象代碼,也是軟件復(fù)用最初級的方式。Python中函數(shù)的定義語句由def關(guān)鍵字、函數(shù)名、括號、參數(shù)(可選)及冒號:組成。下面是幾個簡單的函數(shù)定義語句:

復(fù)制代碼
1 # -*- coding: utf-8 -*-
2 #定義沒有參數(shù)、也沒有返回值的函數(shù)
3  def F1():
4 print 'hello kitty!'
5  #定義有參數(shù)和一個返回值的函數(shù)
6  def F2(x,y):
7 a = x + y
8 return a
9  #定義有多個返回值的函數(shù),用逗號分割不同的返回值,返回結(jié)果是一個元組
10  def F3(x,y):
11 a = x/y
12 b = x%y
13 return a,b
復(fù)制代碼

可能你已經(jīng)注意到了,Python定義函數(shù)的時候并沒有約束參數(shù)的類型,它以最簡單的形式支持了泛型編程。你可以輸入任意類型的數(shù)據(jù)作為參數(shù),只要這些類型支持函數(shù)內(nèi)部的操作(當(dāng)然必要時需要在函數(shù)內(nèi)部做一些類型判斷、異常處理之類的工作)。

3.2  函數(shù)的參數(shù)

3.2.1  C#與Python在函數(shù)參數(shù)定義方面的差別

C#中方法的參數(shù)有四種類型:

(1) 值參數(shù)不含任何修飾符
(2) 引用型參數(shù)以ref 修飾符聲明(Python中沒有對應(yīng)的定義方式)
(3) 輸出參數(shù)以out 修飾符聲明(Python中不需要,因為函數(shù)可以有多個返回值)
(4) 數(shù)組型參數(shù)以params 修飾符聲明

Python中函數(shù)參數(shù)的形式也有四種類型:

(1) f(arg1,arg2,...) 這是最常用的函數(shù)定義方式
(2) f(arg1=value1,arg2=value2,...,argN=valueN) 這種方式為參數(shù)提供了默認(rèn)值,同時在調(diào)用函數(shù)時參數(shù)順序可以變化,也稱為關(guān)鍵字參數(shù)。
(3) f(*arg) arg代表了一個tuple,類似C#中的params修飾符作用,可以接受多個參數(shù)
(4) f(**arg) 傳入的參數(shù)在函數(shù)內(nèi)部是保存在名稱為arg的dict中,調(diào)用的時候需要使用如f(a1=v1,a2=v2)的形式。

可以看出,Python函數(shù)參數(shù)定義與C#相比,最大的兩個區(qū)別是支持關(guān)鍵字參數(shù)和字典參數(shù)。

 

3.29更新:根據(jù)JeffreyZhao提示,C# 4.0 已經(jīng)支持命名參數(shù)(即關(guān)鍵字參數(shù))和可選參數(shù)(即參數(shù)默認(rèn)值),詳情可見生魚片blog上的:《C#4.0新特性:可選參數(shù),命名參數(shù),Dynamic》。在此向兩位致謝。

 

3.2.2  關(guān)鍵字參數(shù)

關(guān)鍵字參數(shù)可以使我們調(diào)用含有很多參數(shù)、同時一些參數(shù)具有默認(rèn)值的Python函數(shù)變得更簡單,也是Python實現(xiàn)函數(shù)重載的一種重要手段(到類與對象部分再詳細(xì)說這個問題)。下面的例子說明了如何定義和調(diào)用含關(guān)鍵字參數(shù)的函數(shù)(引自Guido van Rossum《Python入門》,包括后面的幾個例子):

1 def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
2 print "-- This parrot wouldn't", action,
3 print "if you put", voltage, "Volts through it."
4 print "-- Lovely plumage, the", type
5 print "-- It's", state, "!"


可以用如下幾種方式調(diào)用:

1 parrot(1000) # 缺省值
2  parrot(action = 'VOOOOOM', voltage = 1000000) # 關(guān)鍵字,缺省值,次序可變
3  parrot('a thousand', state = 'pushing up the daisies')# 位置參數(shù),缺省值,關(guān)鍵字
4  parrot('a million', 'bereft of life', 'jump') # 位置參數(shù),缺省值


但以下幾種調(diào)用方式是錯誤的:

1 parrot() # 非缺省的參數(shù)沒有提供
2  parrot(voltage=5.0, 'dead') # 關(guān)鍵字參數(shù)后面又出現(xiàn)了非關(guān)鍵字參數(shù)
3  parrot(110, voltage=220) # 參數(shù)值重復(fù)提供
4  parrot(actor='John Cleese') # 未知關(guān)鍵字

3.2.3  字典參數(shù)

如果形參表中有一個形為**name的形參,在調(diào)用時這個形參可以接收一個字典,字典中包含所有不與任何形參匹配的關(guān)鍵字參數(shù)。例如下面的函數(shù):

1 def cheeseshop(**keywords):
2 for kw in keywords.keys(): print kw, ':', keywords[kw]


就可以象下面這樣調(diào)用:

1 cheeseshop(client='John Cleese',
2 shopkeeper='Michael Palin',
3 sketch='Cheese Shop Sketch')


結(jié)果顯示:

client : John Cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch

3.2.4   函數(shù)參數(shù)調(diào)用的順序

調(diào)用Python函數(shù)時,參數(shù)書寫的順序分別為:非關(guān)鍵字參數(shù),關(guān)鍵字參數(shù),元組參數(shù),字典參數(shù)。請記住以下幾點規(guī)則:

    * 通過位置分配非關(guān)鍵字參數(shù)
    * 通過匹配變量名分配關(guān)鍵字參數(shù)
    * 其他額外的非關(guān)鍵字參數(shù)分配到*name元組中
    * 其他額外的關(guān)鍵字參數(shù)分配到**name的字典中
    * 用默認(rèn)值分配給在調(diào)用時未得到分配的參數(shù)

一般說來,實參表中非關(guān)鍵字參數(shù)在前,關(guān)鍵字參數(shù)在后,關(guān)鍵字名字必須是形參名字。形參有沒有缺省值都可以用關(guān)鍵字參數(shù)的形式調(diào)用。每一形參至多只能對應(yīng)一個實參,因此,已經(jīng)由位置參數(shù)傳入值的形參就不能在同一調(diào)用中再作為關(guān)鍵字參數(shù)。

總之,由于Python的函數(shù)參數(shù)定義和調(diào)用方式太靈活了,所以一開始容易把人搞暈。不過可以慢慢來,你會越來越發(fā)現(xiàn)Python的簡便所在。

3.3  函數(shù)文檔

在C#,可以使用文檔XML標(biāo)記對函數(shù)進(jìn)行注釋,這樣在VS等IDE中,輸入函數(shù)名后就會提示函數(shù)的功能、參數(shù)及返回值等的說明,方便函數(shù)的調(diào)用者。在Python中,也有類似的功能,即文檔字符串(Docstrings)。但Python的文檔字符串不像C#中的文檔XML標(biāo)記那么豐富,基本等同于C#中的<summary>標(biāo)記,下面讓我們一起來通過一個例子了解一下(引自《簡明Python教程》):

復(fù)制代碼
1 def printMax(x, y):
2 '''Prints the maximum of two numbers.
3
4 The two values must be integers.'''
5 x = int(x) # convert to integers, if possible
6   y = int(y)
7
8 if x > y:
9 print x, 'is maximum'
10 else:
11 print y, 'is maximum'
12
13 printMax(3, 5)
14 print printMax.__doc__
復(fù)制代碼

    輸出

    $ python func_doc.py
    5 is maximum
    Prints the maximum of two numbers.

            The two values must be integers.

在上述函數(shù)中,第一個邏輯行的字符串是這個函數(shù)的文檔字符串。文檔字符串的慣例是一個多行字符串,它的首行以大寫字母開始,句號結(jié)尾。第二行是空行,從第三行開始是詳細(xì)的描述,描述對象的調(diào)用方法、參數(shù)說明、返回值等具體信息。

可以使用__doc__(注意雙下劃線)調(diào)用printMax函數(shù)的文檔字符串屬性(屬于函數(shù)的名稱,請記住Python把每一樣?xùn)|西都作為對象,包括這個函數(shù))。它等同于用Python的內(nèi)建函數(shù)help()讀取函數(shù)的說明。很多Python的IDE也依賴于函數(shù)的文檔字符串進(jìn)行代碼的智能提示,因此我們在編寫函數(shù)時應(yīng)養(yǎng)成編寫文檔字符串的習(xí)慣。

3.4  函數(shù)編程

Python中加入了一些在函數(shù)編程語言和Lisp中常見的功能,如匿名函數(shù)、高階函數(shù)及列表內(nèi)涵等,關(guān)于最后一個問題我在《2 運(yùn)算符、表達(dá)式和流程控制》已經(jīng)介紹過了,本章只介紹匿名函數(shù)和高階函數(shù)。

3.4.1  匿名函數(shù)

lambda函數(shù)是匿名函數(shù),用來定義沒有名字的函數(shù)對象。在Python 中,lambda只能包含表達(dá)式:lambda arg1, arg2 ... : expression。lambda 關(guān)鍵字后就是逗號分隔的形參列表,冒號后面是一個表達(dá)式,表達(dá)式求值的結(jié)果為lambda的返回值。

雖然lambda的濫用會嚴(yán)重影響代碼可讀性,不過在適當(dāng)?shù)臅r候使用一下lambda 來減少鍵盤的敲擊還是有其實際意義的,比如做排序的時候,使用data.sort(key=lambda o:o.year)顯然比

1 def get_year(o):
2 return o.year
3 func=get_year(o)
4 data.sort(key=func)

要方便許多。(引自《可愛的Python》)

 

3.29更新:根據(jù)JeffreyZhao提示,重新整理C#中匿名函數(shù)的內(nèi)容(本部分主要參考MSDN,見http://msdn.microsoft.com/zh-cn/library/bb882516.aspx):

在C#中也有匿名函數(shù)功能。在 C# 1.0 中,通過使用在代碼中其他位置定義的方法顯式初始化委托來創(chuàng)建委托的實例。C# 2.0引入了匿名方法的概念,作為一種編寫可在委托調(diào)用中執(zhí)行的未命名內(nèi)聯(lián)語句塊的方式。C# 3.0 引入了 Lambda表達(dá)式,這種表達(dá)式與匿名方法的概念類似,但更具表現(xiàn)力并且更簡練。這兩個功能統(tǒng)稱為“匿名函數(shù)”。通常,針對 .NET 3.5 及更高版本的應(yīng)用程序應(yīng)使用 Lambda 表達(dá)式。

 Lambda 表達(dá)式可以包含表達(dá)式和語句,并且可用于創(chuàng)建委托或表達(dá)式目錄樹類型。所有 Lambda 表達(dá)式都使用 Lambda 運(yùn)算符 =>, 運(yùn)算符的左邊是輸入?yún)?shù)(如果有),右邊包含表達(dá)式或語句塊。可以將此表達(dá)式分配給委托類型,如下所示:

 

1 delegate int del(int i);
2 del myDelegate = x => x * x;
3  int j = myDelegate(5); //j = 25

 

3.4.2  高階函數(shù)

高階函數(shù)(High Order)是函數(shù)式編程的基礎(chǔ),常用的高階函數(shù)有:
(1) 映射,也就是將算法施于容器中的每個元素,將返回值合并為一個新的容器。
(2) 過濾,將算法施于容器中的每個元素,將返回值為真的元素合并為一個新的容器。
(3) 合并,將算法(可能攜帶一個初值)依次施于容器中的每個元素,將返回值作為下一步計算的參數(shù)之一,與下一個元素再計算,直至最終獲得一個總的結(jié)果。

Python通過map、filter、reduce三個內(nèi)置函數(shù)來實現(xiàn)上述三類高階函數(shù)功能。本文不對這三個函數(shù)的用法進(jìn)行詳細(xì)介紹,僅給出它們使用的示例代碼(引自《Python的map、filter、reduce函數(shù)》),請細(xì)細(xì)體會:

復(fù)制代碼
1
2  #coding:utf-8
3  
4  def map_func(lis):
5 return lis + 1
6
7  def filter_func(li):
8 if li % 2 == 0:
9 return True
10 else:
11 return False
12
13  def reduce_func(li, lis):
14 return li + lis
15
16 li = [1,2,3,4,5]
17
18 map_l = map(map_func, li) #將li中所有的數(shù)都+1
19  filter_l = filter(filter_func, li) #得到li中能被2整除的
20  reduce_l = reduce(reduce_func, li) #1+2+3+4+5
21  
22  print map_l
23  print filter_l
24  print reduce_l
復(fù)制代碼

運(yùn)行結(jié)果如下:
C:\>python test1.py
[2, 3, 4, 5, 6]
[2, 4]
15

3.29更新:根據(jù)

 

3.5  小結(jié)

本章討論了Python中函數(shù)的定義和使用方法,要點如下:

(1) Python用def關(guān)鍵字、函數(shù)名、括號、參數(shù)(可選)及冒號定義函數(shù)(要記得函數(shù)體縮進(jìn)呀),函數(shù)可以有0、1或多個返回值;
(2) Python定義函數(shù)不需要(也不能)指定參數(shù)類型,它天生就是泛型的;
(3) Python支持(單獨(dú)或同時使用)普通參數(shù)、關(guān)鍵字參數(shù)、元組參數(shù)和字典參數(shù)四種類型的參數(shù),請學(xué)會靈活使用它們;
(4) 文檔字符串(Docstrings)用于對Python的函數(shù)提供注釋,供自省函數(shù)及IDE調(diào)用;
(5) lambda關(guān)鍵字用來定義匿名函數(shù),它僅支持表達(dá)式,某些情況下可以簡化代碼編寫量,但不要濫用;
(6) Python通過map、filter、reduce三個內(nèi)置函數(shù)實現(xiàn)函數(shù)編程中映射、過濾及合并三類高階函數(shù)功能,但注意map和filter可以用列表內(nèi)涵替代(參見第2章)。

 

進(jìn)一步閱讀的參考:

[1] 本章內(nèi)容較多的參考了Python之父Guido van Rossum的《Python入門》以及國內(nèi)的一本經(jīng)典教程《可愛的Python》,再次向大家推薦這兩本書,在此對作者及譯者致謝。

[2] 限于篇幅和深度,關(guān)于Python函數(shù)中的一些重要主題沒有討論,例如作用域、函數(shù)嵌套、遞歸等,我的觀點是先不要把事情弄得太復(fù)雜,慢慢來總是不錯的。如果你已學(xué)會了本章的內(nèi)容,推薦你進(jìn)一步閱讀《深入Python》,這本書中對很多主題的討論都是(我看多的書中)最深入的。

 

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多