关于 Perl 与 Python 的起源和特点 Perl 是 Practical Extraction and Report Language 的简称由 年 Larry Wall 创建最初的目的是为了在 UNIX 上方便处理报表经过长期的发展已经成为一种全功能的程序设计语言当前最新的版本为 PerlPerl 作为一种自由而强大的编程语言其中心思想是 Theres More Than One Way To Do It(不只一种方法来做这件事 )即「 Tim Toady 」作为一种胶水型语言它具有强大的正则表达式和模式匹配功能以及灵活的数据结构如动态数组Hash 等在语法规则上借鑒了 C/C++BasicPascal 等语言其不足之处在于存在一些冗余语法代码的可读性较差
Python 是一种基于面向对象的解析性交互式的开源编程语言它起源于 年末由 CWI(阿姆斯特丹国家数学和计算机科学研究所)的研究员 Guido van Rossum 创立 年初公开发行其开源式的发行方式促进了 Python 的较快发展目前已经形成了一个强大的社区力量Python 开发者的哲学是用一种方法最好是只有一种方法来做一件事Python 具有简单易学代码规范语法简单可移植性强支持多平台类库丰富等优点
Perl 和 Python 都是开源的但其哲学理念却刚好相反因此常被人们将这两种语言放在一起进行比较下面的篇章将从基本数据类型控制流函数面向对象文本处理等方面对这两种语言进行简单的比较和鑒别
Perl 与 Python 的基本数据类型
脚本语言支持多种数据类型变量无需事先申明类型根据值来动态确定一个变量在程序中可以根据上下文环境的不同存储不同类型的值
Perl 支持的基本数据类型包括标量数组哈希在定义的时分别用 $@% 表示
标量 (scalar)标量是 Perl 中最简单的数据类型大多数标量由数字或字符串组成其中数字类型如整数浮点数等字符串有单引号和双引号内两种形式对长度没有限制两者的区别在于在单引号内 \n 不代表换行而代表反斜线和 n 这两个字符双引号内字符串则可以通过反斜线进行转义字符串的操作符有 拼接操作符和 x 重复操作符等
数组 (Arrays)数组用 @ 定义如 my @array=(abcd); 访问数组的元素用 $array[]在 perl 中数组也可以当做堆栈来处理支持的操作符包括 pop 和 pushshft 和 unshift两组操作的区别在于前者对数组的尾部进行处理而 shift 和 unshift 则针对数组的头部进行处理pop 得到的是数组的最后一个元素如 pop(@array)= d如果数组为空则返回 undef而 shift(@array)=a
哈希也称作关联数组是根据关键码值 (Key value) 而直接进行访问的数据结构用 % 定义如 %my_hash=(key=>name=>zhangage=>)其中键以字符串表示Hash 可以是任意大小
与 hash 相关的函数有
keys返回 hash 的键列表 my @keylist = keys %hash
value返回值列表 my @valuelist = values %hash
each用两个元素的列表返回键值对
复制代码 代码如下:
while(($key$value)= each %hash)
{
print $key =>$value\n;
}
Python 支持五种基本数据类型数字 (Numbers)字符串 (String)列表 (List)元组 (Tuple) 和字典 (Dictionary)其中数字和字符串和 perl 中的标量对应列表和数组对应元组可以看做是不可变的列表字典和 hash 对应
数字 (Numbers)Python 支持五种基本数字类型分别为 int( 有符号整数 ) long( 长整数 ) bool( 布尔值 ) float( 浮点数 ) complex( 复数 )
字符串 (String)Python 与 Perl 一样也支持单引号和双引号字符串但与 Perl 不同转义字符在单引号中也会起作用同时 python 还支持三引号字符串它允许一个字符串跨多行字符串中可以包含换行符制表符以及其他特殊字符三引号字符串常用于注释或者形成文档字符串支持成员操作符 innot in连接操作符 + 以及重复操作符 *Python 字符串可以当做 list支持切片操作符 [][:] 和反向索引如下
如 aString=abcd则 aString[] 的值为 aaString[:]=bc反向索引 aString[]=d
列表 (List)Pyhon 中的列表与 Perl 中的数组相对应列表的定义使用 [] 如 li = [a b mpilgrim z example] 支持动态增加和删除元素以及切片操作
增加元素可以使用 liappend(test)liinsert(new) 以及 liextend([fggf])
删除元素使用 liremove(f) 和 lipop() 但需要注意的是 remove 仅删除首次出现的而 pop 会删除 list 最后的一个元素然后返回删除的元素的值
元组 (Tuple)元组和列表非常相似但用()表示并且元组是不可变的
字典 (Dictionary)字典跟 Perl 中的 hash 一样定义了键值对之间一对一的关系变量可以任意取名Python 会在内部记录其数据类型定义一个字典D={name:JonFamily:SH} 字典中的 key 是不能重复的并且大小写敏感同时字典中的元素是无序的字典也支持增删操作往字典中添加元素 D[age]= 删除元素 del D[name]如果需要删除所有元素可以使用 Dclear() 或者 del D 删除整个字典
Perl 与 Python 的控制结构
在控制结果方面Perl 较 Python 丰富除了支持传统的 if while for 控制结构还支持 until unless foreach 等Python 的控制结构相对要少一些但已经能够满足语言的要求本节对这些控制结构进行详细比较
If 控制结构
Perl 与 Python 都支持 if ifelse ifelse if else 三种结构两者在语法上基本类似但与 Python 不同的是 Perl 中没有 boolean 类型零和空表示 False其余表示 True而 Python 中除了()[]{}None 为 False 之外其他的都是 True同时 Python 直接用缩进表示 block 块
表 if 控制结构
| Perl | Python | if if (expression) {
true_statement;
} if expression:
if_suite
ifelse if (expression) {
true_statement;
} if expression:
if_suite
else:
else_suite Ifelse ifelse if (expression_A) {
A_true_statement;
} elseif (expression_B) {
B_true_statement;
} else {
false_statement;
} if expression:
if_suite
elif expression:
elif_suite
else:
else_suite
Perl 中还支持 unless 条件控制语句基本语法如下
unless (expression) {
stmt_; }
unless 和 if 不同之处在于当条件表达式的值为假的时候才执行同时 unless 后面还能跟 else 语句如
复制代码 代码如下:
unless($mon =~/^Feb/){
print This month has at least thirty days\n;
}else{
print Do you see whats going on here?\n;
}
循环控制结构
For 循环
Perl 中的 for 循环除了支持传统的 for 循环即 for ( 表达式 ; 表达式 ; 表达式 ) 还支持 foreach 语句基本语法为
复制代码 代码如下:
foreach $i (@aList) {
stmt_;
}
python 不支持传统的 for 循环但是提供了强大的循环结构可以遍历序列成员同时 for 循环后面也可以接 else 语句基本语法如下
for inter_var in iterable:
suite_to_repeat
else:
else_statement
while 循环
Perl 循环控制结果还支持 while 和 dowhile 以及 until 形式until 与 while 结构相似区别在于 unitl 会在条件为假的时候重复执行until 语法如下
复制代码 代码如下:
until(expression)
{
statement;
}
而 python 只支持 while 形式但 python 可以在 while 后面接 else 语句语法如下
While condition:
statements
else:
statements
循环控制符
Perl 有三个循环控制操作符分别为 Last next redo
last立即终止循环类似于 c 中的 break在多层循环中只对 last 所在的当前循环块有效
next立刻结束当前这次迭代
redo将控制返回本循环的顶端不经过条件测试也不会进去下一次迭代循环而是重新执行本循环块它与 next 最大的区别在于 next 会正常继续下一次迭代而 redo 会重新执行本次迭代
Python 也有三个循环控制操作符分别为 break continue pass 语句
break与 C 中的 break 类似
continuecontinue 语句并不会退出循环结构而是立即结束本次循环重新开始下一轮循环也就是说跳过循环体中在 continue 语句之后的所有语句继续下一轮循环
pass一般作为占位符或者创建占位程序pass 语句不会执行任何操作
Perl 与 Python 的函数 Perl 和 Python 都支持函数可以传递参数以及在程序中对函数进行调用等下面从函数的定义调用返回值以及参数传递等方面对这两者进行比较
表 Perl 与 Python 函数比较
Perl | Python | 定义
基本语法 sub functionName{
statement;
[return value]
}
基本语法
def functionName(argarg[]):
statement
[return value]
内嵌函数
Python 支持内嵌函数 其方法是在外部函数的定义体内定义函数 但整个函数体都在外部函数的作用域之内
def outfun():
def innerfun():
Print inner fun test
print out fun test 返回值 使用 return 语句显示返回如果没有 return默认返回最后一次运算的结果 使用 return 语句显示返回没有 return 语句默认返回为 None如果函数返回多个对象python 把他们聚集起来并以一个元组返回 调用 & 函数名(参数 参数 )如果声明在前可以省略 &如果用户所定义的子过程与内置函数重名则不能省略 &
如下例必须使用 &chomp 调用
sub chomp{
print it is my chomp\n;
}
直接采用 函数名(参数 参数 )
函数名(参数名 = 值参数名 = 值 ) 函数参数
在子程序调用的后面加上被括号圈引的列表表达式即可所有的参数都会自动存储为 @_ 中其中第一个参数为 $_[] 第二个参数存储 $_[]
传递引用在参数前加入 \ 表示为引用
按照参数声明的关键字顺序直接传递
通过关键字参数 testFun(par=par=)
默认参数
> Python 在传递参数的时候支持默认参数规则是所有的位置参数必须出现在任何一个默认参数之前如
def fun(argdefarg=vardefarg=) 如果在调用的时候没有给出参数值则会使用默认值
变长参数
一种方法是利用非关键字可变长参数 可变长的参数元组必须在位置和默认参数之后 带元组的函数语法如下
def function_name([formal_args]*vargs_tuple):
function_body
其中 * 之后的形参将作为元组传递给函数
另外一种方法是利用关键字变量参数区别是在函数的参数变量里使用 **
def dicVarArgs(argarg=default**theRest):
print formal arg: arg
print formal arg: arg
for eachXtrArg in theRestkeys():
print Xtra arg %s: %s % \(eachXtrArg str(theRest[eachXtrArg])) 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 中所有标识但是标识放到在当前名字空间里
导入模块或包按下面顺序进行路径查找 当前目录
环境变量 PYTHONPATH 所指的目录列表 python 解释器的安装目录
Perl 与 Python 中的 OOP
在 Perl 中类是 Perl 包含有提供对象方法的类而方法是 Perl 的子程序类名是其第一个参数对象是对类中数据项的引用在 Perl 中创建一个新类首先要创建一个包扩展名为 pm 在创建 perl 包的时候程序的最后一个必须为;否则该包不会被 Perl 处理
清单 创建 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;
}
;
[html]
其中 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 );
Perl 类中的方法就 Perl 的子函数规定第一个参数为对象或者被引用的包分为静态方法和虚方法 虚方法通常首先把第一个参数 shift 到变量 self 或 this 中然后将该值作普通的引用使用一是通过该对象的引用 ( 虚方法 )一是直接使用类名 ( 静态方法 )如上例中如果类 Person 中有 getContactList 则可以直接使用 $object>getContactList() 来调用该方法
Perl 支持重载当两个不同的类中含有相同的方法名称的时候可以用 :: 操作符指定使用哪个类中的方法
$mess = Qava::grind(wholelottabags);
Qava::grind($mess wholelottabags);
由于 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};
}
;
调用直接使用 $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 Pfoo()
>>> p = P()
>>> pfoo()
Hi I am Pfoo()
现在创建 C 类 继承于 P
复制代码 代码如下:
class C(P):
def foo(self):
print Hi I am Cfoo()
>>> c = C()
>>> cfoo()
Hi I am Cfoo()
当从一个带构造器 __init()_ 的类派生如果在子类中覆盖了 __init__()当子类被实例化时基类的 __init__() 方法不会被自动调用如果必须调用基类的构造方法可以使用父类名 __init__(self) 方法或者 super( 子类名self)__init__() 如
复制代码 代码如下:
def __init__(self):
super(C self)__init__()
print calling Cs constructor
Python 类和实例支持一些内建函数如
Issubclass(subsup)判断一个类是另一个类的子类或子孙类
isinstance(objobj)判定一个对象是否是另一个给定类的实例
Perl 与 Python 的正则表达式 正则表达式是 perl 比较突出的一大特色perl 中正则表达式有三种形式
匹配m/<regexp>/ (还可以简写为 /<regexp>;/ 略去 m) 替换s/<pattern>/<replacement>/ 为了语法的简化用 /<pattern>/<replacement>/ 表示略去 s
转换tr/<charClass>/<substituteClass>/ 这种形式包含一系列的字符— /<charClass> —同时把它们替换为 <substituteClass>
表 Perl 常用匹配模式
语法 | 说明 | 示例 | 匹配除换行符以外的所有字符 b
c 匹配 bac x? 匹配
次或一次 x 字符串 b?c 匹配 c 或者 bc x* 匹配
次或多次 x 字符串
但匹配可能的最少次数 b*c 匹配 c 或者 bbc x+ 匹配
次或多次 x 字符串
但匹配可能的最少次数 b+c 匹配 bc 或者 bbc
* 匹配
次或一次的任何字符 b
*c 匹配 bgdc 等
+ 匹配
次或多次的任何字符 b
+c 匹配 bgc 等 {m} 匹配刚好是 m 个 的指定字符串 b{
}c 匹配 bbbbbc {m
n} 匹配在 m 个 以上 n 个 以下 的指定字符串 b{
} 匹配 b 或者 bb {m
} 匹配 m 个 以上 的指定字符串 b{
} 匹配 bb 或者 bbb 等 [] 匹配符合 [] 内的字符 b[d]c 匹配 bdc [^] 匹配不符合 [] 内的字符 b[^d]c 匹配 bAc [
] 匹配所有数字字符 b[
]c 匹配 b
c [a
z] 匹配所有小写字母字符 b[a
z]c 匹配 bac ^ 匹配字符开头的字符 ^perl 匹配以 perl 开头的字符 $ 匹配字符结尾的字符 perl$ 匹配以 perl 结尾的字符 \d 匹配一个数字的字符
和 [
] 语法一样 b\dc 匹配 b
c \D 非数字
其他同 \d b\Dc 匹配 bAc \w 英文字母或数字的字符串
和 [a
zA
Z
] 语法一样 b\wc 匹配 b
c 等 \W 非英文字母或数字的字符串
和 [^a
zA
Z
] 语法一样 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) () 这个符号会记住所找寻到的字符串是一个很实用的语法第一个 () 内所找到的字符串变成 $ 这个变量或是 \ 变量第二个 () 内所找到的字符串变成 $ 这个变量或是 \ 变量以此类推下去 b(\d)c 表示匹配的任何数字将存放与 $ 变量中
Python 语言本身不支持正则表达式依赖 re 模块(python 版本被引入)支持正则表达式有搜索和匹配两种方法完成匹配模式re 模块常用的函数和方法有 compliematchsearchfind 与 findall 等在利用 re 进行匹配之前模式必须被编译成 regex 对象
表 Python 常用匹配模式
语法 | 说明 | 示例 | 匹配除换行符 \n 以外的任意字符 b
c 匹配 bac
bdc * 匹配前一个字符
次或多次 b*c 匹配 c
或者 bbbc + 匹配前一个字符
次或多次 b+c 匹配 bc 或者 bbbc ? 匹配前一个字符
或
次 b?c 匹配 c 或者 bc {m} 匹配前一个字符 m 次 b{
}c 匹配 bbc {m
n} 匹配前一个字符 m 至 n 次 b{
}c 匹配 bbc 或者 bbbbc [abc] 匹配 [] 内的任意字符 [bc] 匹配 b 或者 c \d 匹配数字 [
] b\dc 匹配 b
c 等 \D 匹配非数字
等价于 [^\d] b\Dc 匹配 bAc \s 匹配空白字符 b\sc 匹配 b c \S 匹配非空白字符 [\^s] b\Sc 匹配 bac \w 匹配 [A
Za
z
_] b\wc 匹配 bAc 等 \W 等价于 [^\w] b\Wc 匹配 b c \ 转义字符
b\\c 匹配 b\c ^ 匹配字符串开头 ^bc 匹配句首的 bc $ 匹配字符串末尾 bc$ 匹配以 bc 结尾的字符串 \A 仅匹配字符串开头 \Abc 匹配字符串开头的 bc \Z 仅仅匹配字符串末尾 bc\Z 匹配字符串末尾的 bc | 匹配左右表达式任意一个 b|c 匹配 b 或者 c
Perl 与 Python 中的线程 线程是一个单一的执行流程它是所有程序执行过程中最小的控制单位即能被 CPU 所调度的最小任务单元在 Perl 中一个线程的生命周期包括创建运行与退出这三个阶段线程的运行过程与普通函数的执行类似但新建线程的执行与当前线程的执行是并行的
在 Perl 中创建线程有两种方法
清单 使用 threads 包的 create() 方法
复制代码 代码如下:
use threads;
sub say_hello
{
printf(Hello thread! @_\n);
return( rand() );
}
my $t = threads>create( \&say_hello param param );
清单 使用 async{} 块创建线程
复制代码 代码如下:
#!/usr/bin/perl
use threads;
my $t = async{
printf(Hello thread!\n);
};
对于线程的执行控制有两种方式一种是 join()一种是 detach()所谓 join() 就是在主线程中等待子线程的执行返回值然后再继续执行后续代码而在调用线程的 join() 方法之前子线程与主线程的执行是分开的而 detach() 则是告诉解释器主线程不关心子线程的执行结果所以该子线程在完成任务之后就是自动退出同时释放自己所占有的资源而不用主线程再操心
Perl 默认任何数据结构都不是共享的任何新创建的线程都有当前数据的私有拷贝如果要共享数据必须使用 threads::shard 进行显示声明
如
复制代码 代码如下:
my $var :shared = ; # use :share tag to define
my @array :shared = (); # use :share tag to define
my %hash = ();
share(%hash); # use share() funtion to define
同时 Perl 线程还支持锁机制可以使用 lock 方法实现线程间共享数据的锁机制Perl 中的 Thread::Semaphore 包为线程提供了信号量的支持Thread::Queue 包为线程提供了线程安全的队列支持更多使用读者可以自行查阅相关文档
Python 提供了几个用于多线程编程的模块包括 thread threading 和 Queue 等thread 和 threading 模块允许程序员创建和管理线程thread 模块提供了基本的线程和锁的支持而 threading 提供了更高级别功能更强的线程管理的功能Queue 模块允许用户创建一个可以用于多个线程之间共享数据的队列数据结构
Python 的线程创建也有两种方式一是利用 thread 模块的 start_new_thread() 函数来产生新线程
复制代码 代码如下:
import time
import thread
def timer(no interval):
cnt =
while cnt<:
print Thread:(%d) Time:%s/n%(no timectime())
timesleep(interval)
cnt+=
threadexit_thread()
def test(): #Use threadstart_new_thread() to create new threads
threadstart_new_thread(timer ())
threadstart_new_thread(timer ())
if __name__==__main__:
test()
另一种是创建 threadingThread 的子类来包装一个线程对象
复制代码 代码如下:
class timer(threadingThread): # derived from the class threadingThread
def __init__(self num interval):
threadingThread__init__(self)
selfthread_num = num
selfinterval = interval
selfthread_stop = False
def run(self): #Overwrite run() method put what you want the thread do here
while not selfthread_stop:
print Thread Object(%d) Time:%s/n %(selfthread_num timectime())
timesleep(selfinterval)
def stop(self):
selfthread_stop = True
Python 线程中也提供同步机制可以利用 thrading 模块的 threadingRLock 和 hreadingCondition 可以分别实现锁机制和条件变量
其中 acquire() 和 release() 方法分别获取和释放锁
复制代码 代码如下:
def run(self):
global x
lockacquire()
for i in range():
x = x +
timesleep()
print x
lockrelease()
更多关于线程的内容读者可查阅相关文档
总结 本文从 Perl 和 Python 的起源基本数据类型控制结构函数包与模块面向对象正则表达式以及线程等方面进行了比较从而给需要同时掌握这两种脚本语言的开发人员一定参考以便更好的理解与应用
参考资料 学习
在 developerWorks Linux 专区寻找为 Linux 开发人员(包括 Linux 新手入门)准备的更多参考资料查阅我们 最受欢迎的文章和教程
在 developerWorks 上查阅所有 Linux 技巧和 Linux 教程
随时关注 developerWorks 技术活动和 网络广播
参考 Tutorial Perl官方文档关注更多 Perl 动态
参考 Perl Document了解 Perl 基本语法
参考 Tutorial Python查看 Python 的官方文档