關於 Perl 與 Python 的起源和特點
Perl 是 Practical Extraction and Report Language 的簡稱,由 1987 年 Larry Wall 創建,最初的目的是為了在 UNIX 上方便處理報表,經過長期的發展已經成為一種全功能的程序設計語言,當前最新的版本為 Perl5.14.1,Perl 作為一種自由而強大的編程語言,其中心思想是: There's More Than One Way To Do It。(不只一種方法?磣穌餳? ),即「 Tim Toady 」。作為一種“膠水型”語言,它具有強大的正則表達式和模式匹配功能以及靈活的數據結構,如動態數組、Hash 等,在語法規則上借鑒了 C/C++、Basic、Pascal 等語言,其不足之處在於存在一些冗餘語法,代碼的可讀性較差。
Python 是一種基於面向對象的解析性互動式的開源編程語言,它起源於 1989 年末由 CWI(阿姆斯特丹國家數學和計算機科學研究所)的研究員 Guido van Rossum 創立,1991 年初公開發行,其開源式的發行方式促進了 Python 的較快發展,目前已經形成了一個強大的社區力量。Python 開發者的哲學是“用一種方法,最好是只有一種方法來做一件事”。Python 具有簡單易學、代碼規範、語法簡單、可移植性強、支持多平台、類庫豐富等優點。
Perl 和 Python 都是開源的,但其哲學理念卻剛好相反,因此常被人們將這兩種語言放在一起進行比較。下面的篇章將從基本數據類型、控制流、函數、面向對象、文本處理等方面對這兩種語言進行簡單的比較和鑒別。
回頁首
Perl 與 Python 的基本數據類型
腳本語言支持多種數據類型,變數無需事先申明,類型根據值來動態確定,一個變數在程序中可以根據上下文環境的不同存儲不同類型的值。
Perl 支持的基本數據類型包括:標量、數組、哈希。在定義的時分別用 $、@、% 表示。
Python 支持五種基本數據類型:數字 (Numbers)、字元串 (String)、列表 (List)、元組 (Tuple) 和字典 (Dictionary)。其中數字和字元串和 perl 中的標量對應,列表和數組對應,元組可以看做是不可變的列表,字典和 hash 對應。
回頁首
Perl 與 Python 的控制結構
在控制結果方面,Perl 較 Python 豐富,除了支持傳統的 if 、while 、for 控制結構,還支持 until 、unless 、foreach 等,Python 的控制結構相對要少一些,但已經能夠滿足語言的要求。本節對這些控制結構進行詳細比較。
If 控制結構:
Perl 與 Python 都支持 if 、if-else 、if-else if- else 三種結構,兩者在語法上基本類似,但與 Python 不同的是 Perl 中沒有 boolean 類型,零和空表示 False,其餘表示 True,而 Python 中除了''、""、0、()、[]、{}、None 為 False 之外,其他的都是 True。同時 Python 直接用縮進表示 block 塊。
表 1. if 控制結構
Perl | Python | |
---|---|---|
if | if (expression) { true_statement; } | if expression: if_suite |
if-else | if (expression) { true_statement; } | if expression: if_suite else: else_suite |
If-else if-else | if (expression_A) { A_true_statement; } elseif (expression_B) { B_true_statement; } else { false_statement; } | if expression1: if_suite elif expression2: elif_suite else: else_suite |
Perl 中還支持 unless 條件控制語句,基本語法如下:
unless (expression) {
stmt_1; }
unless 和 if 不同之處在於當條件表達式的值為假的時候才執行,同時 unless 後面還能跟 else 語句。如:
unless($mon =~/^Feb/){ print “This month has at least thirty days.\n”; }else{ print “Do you see what's going on here?\n”; } |
循環控制結構:
Perl 中的 for 循環除了支持傳統的 for 循環,即 for ( 表達式 1; 表達式 2; 表達式 3) ,還支持 foreach 語句,基本語法為:
foreach $i (@aList) { stmt_1; } |
python 不支持傳統的 for 循環,但是提供了強大的循環結構可以遍歷序列成員,同時 for 循環後面也可以接 else 語句,基本語法如下:
for inter_var in iterable: suite_to_repeat else: else_statement |
Perl 循環控制結果還支持 while 和 do-while 以及 until 形式,until 與 while 結構相似,區別在於 unitl 會在條件為假的時候重複執行。until 語法如下:
until(expression) { statement; } |
而 python 只支持 while 形式,但 python 可以在 while 後面接 else 語句。語法如下:
While condition: statements else: statements |
循環控制符
Perl 有三個循環控制操作符,分別為 Last 、next 、redo。
Python 也有三個循環控制操作符,分別為 break 、continue 、pass 語句。
回頁首
Perl 與 Python 的函數
Perl 和 Python 都支持函數,可以傳遞參數以及在程序中對函數進行調用等。下面從函數的定義,調用,返回值以及參數傳遞等方面對這兩者進行比較。
表 2. Perl 與 Python 函數比較
Perl | Python | |
---|---|---|
定義 |
statement; [return value] } |
|
返回值 | 使用 return 語句顯示返回;如果沒有 return,默認返回最後一次運算的結果 | 使用 return 語句顯示返回,沒有 return 語句,默認返回為 None。如果函數返回多個對象,python 把他們聚集起來並以一個元組返回。 |
調用 | & 函數名(參數 1,參數 2,...),如果聲明在前,可以省略 &。如果用戶所定義的子過程與內置函數重名,則不能省略 &。 如下例必須使用 &chomp 調用: sub chomp{ print “it is my chomp\n”; } |
|
函數參數 |
|
|
回頁首
Perl 與 Python 的包與模塊
Perl 程序把變數和子程序的名稱存貯到符號表中,Perl 的符號表中名字的集合就稱為 Perl 包 (package)。定義語法為:package mypack;每個符號表有其自己的一組變數、子程序名,各組名字是不相關的,因此可以在不同的 Perl 包中使用相同的變數名,而代表的是不同的變數。Perl 模塊有兩種來源,一種是隨 Perl 發行版本一同打包的,另外就是用 CPAN 中下載的。Perl 模塊和包的概念並不清晰,兩者有時可以混用。在程序中使用模塊的操作稱為導入模塊;導入模塊關鍵字 use;如:use ModuleName;模塊被導入后,其中的子程序和變數就可以直接使用了;要取消一個已經導入了的模塊,可以使用關鍵字 no;如:no ModuleName。
一個 .py 文件就是一個 python 模塊。把一堆相關的 python 模塊放在一個目錄下,再加上一個 __init__.py 文件就構成了一個 python 包。在 Python 另一個程序中導入模塊用 import module 或者 from module import *,兩者的區別在於:import module 會導入 module 這個模塊里的所有標識,但是這些標識現在都在 module 名字空間下。from module import * 也會導入 module 中所有標識,但是標識放到在當前名字空間里。
導入模塊或包按下面順序進行路徑查找:
1. 當前目錄
2. 環境變數 PYTHONPATH 所指的目錄列表 3.python 解釋器的安裝目錄
回頁首
Perl 與 Python 中的 OOP
在 Perl 中,類是 Perl 包,含有提供對象方法的類,而方法是 Perl 的子程序,類名是其第一個參數,對象是對類中數據項的引用。在 Perl 中創建一個新類,首先要創建一個包,擴展名為 .pm, 在創建 perl 包的時候程序的最後一個必須為"1;";否則該包不會被 Perl 處理。
清單 1. 創建 perl 的類和對象
package person; use strict; sub new { my $class = shift(); print("CLASS = $class\n"); my $self = {}; $self->{"name"} = shift(); $self->{"sex"} = shift(); bless $self, $class; return $self; } 1; |
其中 new() 方法是對象的構造函數,是創建該類的對象實例必須被調用的,它返回該對象的引用。將類名與引用相結合稱為”bless”一個對象,其語法為:bless YeReference [,classname]
YeReference 是對被”祝福”的對象的引用,classname 是可選項,指定對象獲取方法的包名,其預設值為當前包名。也可以通過函數 bless 來聲明一個構造函數。
sub new { my $class = shift; my $self = {}; bless $self, $class; return $self; } |
創建一個對象可以直接使用 new 關鍵字。$object = new Person( "mohand", "sam", 345);
Perl 類中的方法就 Perl 的子函數,規定第一個參數為對象或者被引用的包,分為靜態方法和虛方法。 虛方法通常首先把第一個參數 shift 到變數 self 或 this 中,然後將該值作普通的引用使用。一是通過該對象的引用 ( 虛方法 ),一是直接使用類名 ( 靜態方法 )。如上例中如果類 Person 中有 getContactList 則可以直接使用 $object->getContactList() 來調用該方法。
Perl 支持重載,當兩個不同的類中含有相同的方法名稱的時候,可以用 :: 操作符指定使用哪個類中的方法。
$mess = Qava::grind("whole","lotta","bags");
Qava::grind($mess, "whole","lotta","bags");
由於 Perl 採用了簡單的、基於引用的垃圾回收系統。Perl 跟蹤對象的鏈接數目,當某對象的最後一個應用釋放到內存池時,該對象就自動銷毀。因此一般不需要定義類的析構函數。
Perl 通過數組 @ISA 支持繼承。
package Employee; use Person; use strict; our @ISA = qw(Person); # inherits from Person |
當子類繼承父類的時候,繼承了父類的所有方法,但子類也可以覆蓋父類的方法。如加入 Employee 想覆蓋父類的 getFirstName:
#!/usr/bin/perl package Employee; use Person; use strict; our @ISA = qw(Person); # inherits from Person # Override helper function sub getFirstName { my( $self ) = @_; # This is child class function. print "This is child class helper function\n"; return $self->{_firstName}; } 1; |
調用直接使用 $firstName = $object->getFirstName(); 如果要調用父類的 getFirstName,則可以使用 $object->Person::getFirstName();
在 Python 中創建一個類的基本語法為 :
class className(bases): classBody |
參數 base 可以是一個單繼承或者多繼承的父類,object 是所有類的父類,位於類繼承結構的最上層。類的構造函數為 __init__(),其中構造函數中 self 會作為第一個默認的參數。而類的析構函數則是 __del__(),訪問類的方法和屬性可以直接使用 . 訪問符。
Python 不支持純虛函數或抽象方法,並且聲明和定義沒有本質區別。一般或者 Python 類的屬性可以通過 __dict__ 或者 dict()訪問。常見屬性有 __name__ ,__doc__,__base__,__dict__。Python 中創建一個類的實例,不需要關鍵之 new,直接使用類名 () 即可。如 c=myclass()。
Python 不僅僅支持單繼承和多繼承,同時還支持方法的覆蓋 .
class P(object): def foo(self): print 'Hi, I am P-foo()' >>> p = P() >>> p.foo() Hi, I am P-foo() |
現在創建 C 類 , 繼承於 P
class C(P): def foo(self): print 'Hi, I am C-foo()' >>> c = C() >>> c.foo() Hi, I am C-foo() |
當從一個帶構造器 __init()_ 的類派生,如果在子類中覆蓋了 __init__(),當子類被實例化時,基類的 __init__() 方法不會被自動調用。如果必須調用基類的構造方法,可以使用父類名 .__init__(self) 方法或者 super( 子類名,self).__init__()。 如
def __init__(self): super(C, self).__init__() print "calling C's constructor" |
Python 類和實例支持一些內建函數,如
Issubclass(sub,sup):判斷一個類是另一個類的子類或子孫類;
isinstance(obj1,obj2):判定一個對象是否是另一個給定類的實例;
回頁首
Perl 與 Python 的正則表達式
正則表達式是 perl 比較突出的一大特色,perl 中正則表達式有三種形式:
匹配:m/<regexp>/ (還可以簡寫為 /<regexp>;/ ,略去 m) 替換:s/<pattern>/<replacement>/ ,為了語法的簡化用 /<pattern>/<replacement>/ 表示,略去 s
轉換:tr/<charClass>/<substituteClass>/ 這種形式包含一系列的字元— /<charClass> —同時把它們替換為 <substituteClass>。
表 3. Perl 常用匹配模式
語法 | 說明 | 示例 |
---|---|---|
. | 匹配除換行符以外的所有字元 | b.c 匹配 bac |
x? | 匹配 0 次或一次 x 字元串 | b?c 匹配 c 或者 bc |
x* | 匹配 0 次或多次 x 字元串,但匹配可能的最少次數 | b*c 匹配 c 或者 bbc |
x+ | 匹配 1 次或多次 x 字元串,但匹配可能的最少次數 | b+c 匹配 bc 或者 bbc |
.* | 匹配 0 次或一次的任何字元 | b.*c 匹配 bgdc 等 |
.+ | 匹配 1 次或多次的任何字元 | b.+c 匹配 bgc 等 |
{m} | 匹配剛好是 m 個 的指定字元串 | b{5}c 匹配 bbbbbc |
{m,n} | 匹配在 m 個 以上 n 個 以下 的指定字元串 | b{1,2} 匹配 b 或者 bb |
{m,} | 匹配 m 個 以上 的指定字元串 | b{2,} 匹配 bb 或者 bbb 等 |
[] | 匹配符合 [] 內的字元 | b[d]c 匹配 bdc |
[^] | 匹配不符合 [] 內的字元 | b[^d]c 匹配 bAc |
[0-9] | 匹配所有數字字元 | b[0-9]c 匹配 b1c |
[a-z] | 匹配所有小寫字母字元 | b[a-z]c 匹配 bac |
^ | 匹配字元開頭的字元 | ^perl 匹配以 perl 開頭的字元 |
$ | 匹配字元結尾的字元 | perl$ 匹配以 perl 結尾的字元 |
\d | 匹配一個數字的字元,和 [0-9] 語法一樣 | b\dc 匹配 b1c |
\D | 非數字,其他同 \d | b\Dc 匹配 bAc |
\w | 英文字母或數字的字元串,和 [a-zA-Z0-9] 語法一樣 | b\wc 匹配 b1c 等 |
\W | 非英文字母或數字的字元串,和 [^a-zA-Z0-9] 語法一樣 | b\Wc 匹配 b c |
\s | 空格,和 [\n\t\r\f] 語法一樣 | b\sc 匹配 b c |
\S | 非空格,和 [^\n\t\r\f] 語法一樣 | b\Sc 匹配 bac 等 |
\b | 匹配以英文字母 , 數字為邊界的字元串 | \bbc\b 匹配 bc 但不匹配 bca |
\B | 匹配不以英文字母 , 數值為邊界的字元串 | sa\B 將匹配 sand 和 Sally 等字元串,而不能匹配 Melissa. |
a|b|c | 匹配符合 a 字元 或是 b 字元 或是 c 字元 的字元串 abc 匹配含有 abc 的字元串 | 匹配 a 或者 b 或者 c 等 |
(pattern) () | 這個符號會記住所找尋到的字元串,是一個很實用的語法。第一個 () 內所找到的字元串變成 $1 這個變數或是 \1 變數,第二個 () 內所找到的字元串變成 $2 這個變數或是 \2 變數,以此類推下去。 | b(\d)c 表示匹配的任何數字將存放與 $1 變數中 |
[火星人 ] Perl 與 Python 之間的一些異同已經有3939次圍觀