标签:
转自:http://blog.chinaunix.net/xmlrpc.php?r=blog/article&id=4662991&uid=608135
作为万年Perl 党表示最近开始学Python 了,下面会记录一下学习中Python 和Perl 的对比,如果你也是一个Perl 用户,看过了也会对Python 有一个大致的印象吧。 事实上,写着写着我发现如果你是一名Python 用户,看完后也会对Perl 有一个大致的了解 _(:з)∠)_ 基本数据类型 1. Perl 中的标量 a. Perl 中的标量在Python 中对应为数字类型和字符串类型 Perl 的标量是字符串还是数值会根据上下文自动判断,但是Python 不会这样做。 下面的代码是你在Perl 中习以为常的操作 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 my ($string, $number) = ("1", ); $number = $string + "1"; # $string 和"1" 都被解释为数值 say $number; $string = $number.1; # $number 和1 都被解释为字符串 say $string; 但是Python 中你必须显式的指定数据类型 [python] view plaincopy在CODE上查看代码片派生到我的代码片 string = "1" number = int (string) + 1 # 必须显式转换为数值类型 print (number) string = str (number) + "1" # 同样必须显式转换为字符串 print (string) b. Perl 的标量不支持下标运算,但是Python 的字符串可以 Python 中你可以很方便的用下标索引字符串(而且和Perl 中的列表一样也支持用负数做反向索引) [python] view plaincopy在CODE上查看代码片派生到我的代码片 s = "A string" print (s[2:]) 但是Perl 的标量就无法这样操作,相同的操作必须用列表切片完成 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 $_ = "A string"; say ((split //)[2..split //]); c. Perl 中的heredoc 式标量赋值在Python 中可以使用三引号运算符完成 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 @_ = < Everthing is in the array END say "@_"; 下面是等价的Python 代码,注意第一行是紧跟三引号运算符之后的 [python] view plaincopy在CODE上查看代码片派生到我的代码片 string = ‘‘‘‘‘Everthing is in the array ‘‘‘ print (string) 2. Perl 中的列表 a. Perl 中的列表Python 中对应为列表和元组 下面是Python 中倒序排序一个列表的操作 [python] view plaincopy在CODE上查看代码片派生到我的代码片 my_list = ["Hello", "Python"] my_list.append ("World") my_list += ["!"] print (my_list) my_list.sort (); my_list.reverse (); for string in my_list: print (string) 对应的Perl 同性质操作的版本 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 @_ = qw/Hello Perl/; push @_, ‘World‘; @_ = (@_, ‘!‘); print "@_\n"; @_ = reverse sort @_; say for @_; b. 常用的splice 操作在Python 中可以用过index () 方法和del 操作完成 下面是Perl 中常用的splice 操作 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 @_ = qw/Hello Perl !/; splice @_, 2, 0, "World"; # 插入元素 say "@_"; my @removed = splice @_, 1, 2; # 提取一段元素并在原列表删除 print "@_\n@removed\n"; Python 中对应的操作 [python] view plaincopy在CODE上查看代码片派生到我的代码片 my_list = ["Hello", "Python", "!"] my_list.insert (2, "World") # 插入元素 print (my_list) removed = my_list[1:2] # 提取一段元素 del my_list[1:2] # 并在原列表删除 print (my_list) print (removed) 注意:Python 中元组和列表的区别 元组创建后是只读的,但是列表随时都可以被修改。 3. Perl 中的哈希 a. Perl 中的哈希Python 中对应为字典和集合 一个Perl 哈希按照键值升序遍历的操作如下 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 my %hash = ( "first" => 1, "second" => 2, "third" => 3 ); say "$_ => $hash{$_}" for sort keys %hash; Python 中代码如下(注意定义变为花括号) [python] view plaincopy在CODE上查看代码片派生到我的代码片 my_hash = { "first" : 1, "second" : 2, "third" : 3 } items = sorted (my_hash.items (), key=lambda e:e[1], reverse=False) for item in items: print (item[0], ‘:‘, item[1]) 注意:Python 中集合与字典的不同之处 (a) 仅包含键,但是没有值 (b) set 可变,但是frozenset 不可变(如其名) 4. Python 强类型的判断和赋值 一个非常大的不同之处:Perl 中赋值号默认的行为是拷贝,但是Python 中赋值号会创建一个对象的引用。 另外,因为和弱类型的Perl 不同,Python 是一门强类型语言,所以也有判断对象类型的必要。 下面代码演示了这些区别,首先是一段Python 代码 [python] view plaincopy在CODE上查看代码片派生到我的代码片 lst = [1, 2, 3] lst2 = lst # lst2 是lst 的一个引用 print (lst) lst2[1] = 2.5 # 所以修改lst2 也会引起lst 的变化 print (lst) lst3 = copy.deepcopy (lst) # lst3 是lst 的一个深拷贝 lst3[1] = 2 print (lst) # 修改lst3 不会引起lst 的变化 # 因为Python 是强类型语言,所以需要类型判断操作 if lst == lst2: # 如果s 和s2 值相同 print ("lst equal to lst2") if lst is lst2: # 如果s 和s2 是指向同一个对象的引用 print ("lst and lst2 is the same") if type (lst) is type (lst3): # 如果s 和s3 类型相同 print ("lst and lst3 has same type") 下面是与之完全等价的Perl 代码,对比一下你就会很快了解其中的差别 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 my @lst = (1..3); my $lst2 = \@lst; # lst2 是lst 的一个引用 say "@$lst2"; $lst2->[1] = 2.5; # 所以修改lst2 也会引起lst 的变化 say "@$lst2"; my @lst3 = @lst; # lst3 是lst 的一个深拷贝 $lst3[1] = 2; say "@lst"; # 修改lst3 不会引起lst 的变化 =pod 因为Perl 是弱类型语言,所以不需要类型判断操作 但是Perl 中仍然可以做这样的操作——虽然没什么意义 =cut say "lst equal to lst2" if @lst == @$lst2; # 如果s 和s2 值相同 say "lst and lst2 is the same" if \@lst == $lst2; # 如果s 和s2 是指向同一个对象的引用 say "lst and lst3 has same type" if ref \@lst eq ref \@lst3; # 如果s 和s3 类型相同 5. Perl 中的“上下文” 上下文的判断几乎已经成了一名Perl 用户不可或缺的第六感,一个显而易见的例子是当你定义一个列表 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 my @lst = (1..3); 当你循环遍历的时候,你深知把for 循环 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 say for @lst; # 列表上下文 替换为While 循环 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 say while @lst; # 标量上下文 究竟会得到什么灾难性的后果。 但是在Python 中你不必担心这个:Python 对于数据类型的解释很明确,不会因为上下文环境不同而改变,当你定义一个列表 [python] view plaincopy在CODE上查看代码片派生到我的代码片 lst = [1, 2, 3] 之后,你永远不必担心在什么特殊的上下文中lst 会被Python 解释为数值3。 面向对象编程 1. 几点明显的异同 Perl 和Python 的面向对象给人的感觉是后者明显比前者更加规范,下面是自己感受最明显的几点异同。 a. 真的是面向对象么? 1). Perl 中的“面向对象”更像是“面向过程”的文字游戏:类通过包实现、方法通过包中定义的函数实现、类的继承和方法的重载通过@ISA 列表查找循序实现、私有方法通过指向匿名函数的my 引用实现(因为my变量是本文件可见的)、运算符重载通过指向函数的引用实现、对象中成员变量的访问通过bless 到类名的引用实现……这样如果说有好处,那就是编程可以非常灵活——你可以用一个父类的多个子类共同继承出一个类(例如从哺乳动物中人类和猫类继承出一种新生物),Perl 完全对这种行为不在意,只要你确信这种近亲结婚的方式真的是你需要达到的目的。当然坏处显而易见——你可以轻而易举把代码写的糟糕透顶。所以Perl 的“面向对象”给人的感觉只是“面向过程”的另一种玩法——面向过程的本质没变,但是面向对象的效果达到了。 2). Python 中的“面向对象”比Perl 要严谨和规范许多,非常类似于Java,如果你熟悉Java 或者C++,那么你会很好理解Python 的面向对象编程。 b. 包和类 1). Perl 中两者完全等价,一个包就是一个类(pm 是Perl 模块的意思,但是它又被叫做包,而包就是类的意思 ← ←)。 2). Python 中一个包可以包含多个模块,一个模块可以包含多个类。 c. 静态方法 Perl 和Python 中静态方法都是第一个参数不是类的引用的方法,但是稍有不同: 1). Perl 中静态方法第一个参数是类名,可以通过bless 新的引用到类名来操作对象类型(例如你在构造方法里做的那样)。 2). Python 中静态方法完全无法操作对象类型。 d. 私有方法: 1). Perl 中的私有方法通过my 变量只有当前文件可见的性质,用保存匿名函数的my 引用来达到“私有”的目的(“面向对象”的文字游戏)。 2). Python 中吧以“__”开头的方法都当作私有方法,通过方法名会变成"_类名__方法名" 的形式来避免其他类调用该方法,但是你仍然可以通过手动变换后的方法名直接调用私有方法。 e. 方法的传参: 1). Perl 中一般将散列的引用bless 到类名,所以传参可以十分灵活,如果构造函数允许,参数个数和位置根本无关紧要,但是随之造成的问题就是可能引发混乱。 2). Python 中方法声明无法把无默认值的参数放在有默认值的参数后面,但是因为实参可以通过给出参数名手动显式指定,所以次序也可以无关紧要。 f. 运算符重载: 1). Perl 通过use overload 模块指定方法的引用来达到重载运算符的目的。 2). Python 中通过一组特殊名称的方法来重载运算符。 g. 父类方法重载: 1). Perl 中通过@ISA 列表的搜索顺序来达到重载父类方法的目的(子类的同名方法会被优先搜索到),并且可以显式SUPER 伪类访问被覆盖的基类方法(就如你经常在析构方法中做的一样)。 2). Python 的重载更加正式,形式非常类似于C++。 h. 继承: 1). Perl 的继承只是操作了@ISA 列表,子类中没有的方法会在@ISA 中寻找方法名,因此这种行为得到的结果和面向对象编程的继承相同。UNIVERSAL 是所有类的祖先类,提供了isa 方法用来测试继承关系。 2). Python 的继承类似于C++,显式指定了要继承的父类,object 类是所有类的祖先类,提供issubclass 方法用来测试继承关系。 2. 一个演示异同的例子 下面的两个例子都会有相同的输出,演示了Perl 和Python 中类的构造、析构、公有方法、私有方法、运算符重载、继承、父类方法重载等。 下面是预期的输出 [plain] view plaincopy在CODE上查看代码片派生到我的代码片 =My name‘s Lucy, 2 years old. Adoption me please. +I am hungry offen. -My name‘s Leia, 1 years old. My host is iSpeller. +I hate milk but my host give me offen. -My name‘s Lucy, 2 years old. My host is iSpeller. +I hate milk but my host give me offen. -------------------------------------------------------- 下面是你熟悉的Perl [plain] view plaincopy在CODE上查看代码片派生到我的代码片 #!/usr/bin/perl # ======================== # filename: main.pm # main 类,演示了: # 类的实例化 # ======================= package main; use warnings; use strict; use 5.010; use Dog; use Pet_Dog; push @INC, ‘.‘; # 一条叫Lucy 的汪星人 my $lucy = Dog->new (name => ‘Lucy‘, age => 2); $lucy->say_hello; $lucy->my_secret; # 第一条宠物汪,默认为1 岁的leia my $pet_leia = Pet_Dog->new (host => ‘iSpeller‘); $pet_leia->say_hello; $pet_leia->my_secret; # 纳入第二个宠物汪 # 调用了Pet 类运算符重载函数 my $pet_lucy = $lucy + "iSpeller"; $pet_lucy->say_hello; $pet_lucy->my_secret; 1; [plain] view plaincopy在CODE上查看代码片派生到我的代码片 # ======================== # filename: Dog.pm # Pet 类,演示了: # 构造、析构方法 # 公有、私有方法 # 重载 # ======================== package Dog; use strict; use warnings; use 5.010; use overload ‘+‘ => \&meet; # 重载加号运算符 # 构造方法 # 是静态方法,第一个参数为类名 sub new { my $type = shift; my $class = ref $type || $type; # 如有用户实例变量则覆盖默认属性 my $self = { name => ‘Leia‘, age => 1, is_pet => 0, @_ }; bless $self, $class; return $self; } # 析构方法 # 是虚方法,第一个参数为类的引用 sub DESTROY { my $self = shift; # 调用父类析构方法 $self->SUPER::DESTROY if $self->can (‘SUPER::DESTROY‘); } # 公有方法 sub say_hello { my $self = shift; print ‘=‘ if $self->isa ("UNIVERSAL"); # UNIVERSAL 类是所有类的祖先类 printf "My name‘s %s, %d years old. %s.\n", $self->{name}, $self->{age}, $self->{is_pet} ? "I am a pet dot" : "Adoption me please"; } # 私有方法 my $say_secret = sub { my $self = shift; say ‘+‘, $self->{is_pet} ? "I hate milk but my host give me offen." : "I am hungry offen."; }; # 私有方法只能在本文件内由其他方法访问(my $say_secret) sub my_secret { my $self = shift; $self->$say_secret; } # 重载加号运算符,返回成为宠物后的自身 sub meet { my $self = shift; my @property = %$self; my $new = Pet_Dog->new (@property, host => shift); return $new; } 1; [plain] view plaincopy在CODE上查看代码片派生到我的代码片 # ======================== # filename: Pet_Dog.pm # Pet_Dog 类,继承自Dog 类,演示了: # 继承、父类方法的重载 # ======================= package Pet_Dog; use strict; use warnings; use 5.010; use base qw/Dog/; # 继承自Dog 类 sub new { # 调用父类的构造方法 # 因为shift 得到的是子类的类名,所以不需要重新bless my $self = Dog::new (shift, host => "none", @_, is_pet => 1); return $self; } # 重载父类的say_hello (虚)方法 sub say_hello { my $self = shift; print ‘-‘ if $self->isa ("Dog"); # 继承关系测试 printf "My name‘s %s, %d years old. My host is %s.\n", $self->{name}, $self->{age}, $self->{host}; } 1; -------------------------------------------------------- 下面是完全等价的Python [python] view plaincopy在CODE上查看代码片派生到我的代码片 #!/usr/bin/python3 # filename: main.py # ======================== # Dog 类,演示了: # 构造、析构方法 # 公有、私有方法 # 重载 # ======================== class Dog: # 构造方法 # 是私有方法,因为方法名以"__" 开头 def __init__ (self, name = "Leia", age = 1, is_pet = 0): # 如有用户实例变量则覆盖默认属性 self.name = name self.age = age self.is_pet = is_pet # 析构方法 # 静态方法,不会操作实例类型 # 类似Perl,第一个参数不是引用,所以你无法通过第一个参数来引用实例变量 @staticmethod def __del__ (): pass # 公有方法 def say_hello (self): if issubclass (Dog, object): print ("=", end=‘‘) print ("My name‘s %s, %d years old. %s." % (self.name, self.age, # Python 中没有三目运算符,可以用下面的形式替代 "I am a pet dog" if self.is_pet else "Adoption me please")) # 私有方法 def __say_secret (self): print ("+%s." % ("I hate milk but my host give me offen" if self.is_pet else "I am hungry offen")) # 私有方法只能在本类内由其他方法访问 def my_secret (self): self.__say_secret () # 重载加号运算符为和对方恋爱,返回成为女朋友后的自身 def __add__ (self, other): new = Pet_Dog (self.name, self.age, 1, other) return (new) # ======================== # Pet_Dog 类,继承自Dog 类,演示了: # 继承、父类方法的重载 # ======================== class Pet_Dog (Dog): # 调用父类的构造方法 # 之后初始化子类变量 def __init__ (self, name = "Leia", age = 1, is_pet = 1, host = "none"): Dog.__init__ (self, name, age, is_pet) self.host = host # 重载父类的say_hello (虚)方法 def say_hello (self): if issubclass (Pet_Dog, Dog): print ("-", end=‘‘) print ("My name‘s %s, %d years old. My host is %s." % (self.name, self.age, self.host)) ‘‘‘‘‘ 程序开始,Python 的类型不允许在定义之前使用 然而Python 似乎又不区分声明和定义 演示了类的实例化 ‘‘‘ # 一条叫Lucy 的汪星人 lucy = Dog ("Lucy", 2) lucy.say_hello () lucy.my_secret () # 第一条宠物汪,默认为1 岁的leia pet_dog_leia = Pet_Dog (host = "iSpeller"); pet_dog_leia.say_hello () pet_dog_leia.my_secret () # 纳入第二宠物汪 # 调用了Pet 类运算符重载函数 pet_dog_lucy = lucy + "iSpeller" pet_dog_lucy.say_hello () pet_dog_lucy.my_secret () 转载自:http://blog.csdn.net/iSpeller/article/details/23198211
作为万年Perl 党表示最近开始学Python 了,下面会记录一下学习中Python 和Perl 的对比,如果你也是一个Perl 用户,看过了也会对Python 有一个大致的印象吧。
事实上,写着写着我发现如果你是一名Python 用户,看完后也会对Perl 有一个大致的了解 _(:з)∠)_
a. Perl 中的标量在Python 中对应为数字类型和字符串类型
Perl 的标量是字符串还是数值会根据上下文自动判断,但是Python 不会这样做。
下面的代码是你在Perl 中习以为常的操作
但是Python 中你必须显式的指定数据类型
b. Perl 的标量不支持下标运算,但是Python 的字符串可以
Python 中你可以很方便的用下标索引字符串(而且和Perl 中的列表一样也支持用负数做反向索引)
但是Perl 的标量就无法这样操作,相同的操作必须用列表切片完成
c. Perl 中的heredoc 式标量赋值在Python 中可以使用三引号运算符完成
下面是等价的Python 代码,注意第一行是紧跟三引号运算符之后的
a. Perl 中的列表Python 中对应为列表和元组
下面是Python 中倒序排序一个列表的操作
对应的Perl 同性质操作的版本
b. 常用的splice 操作在Python 中可以用过index () 方法和del 操作完成
下面是Perl 中常用的splice 操作
Python 中对应的操作
注意:Python 中元组和列表的区别
元组创建后是只读的,但是列表随时都可以被修改。
a. Perl 中的哈希Python 中对应为字典和集合
一个Perl 哈希按照键值升序遍历的操作如下
Python 中代码如下(注意定义变为花括号)
注意:Python 中集合与字典的不同之处
(a) 仅包含键,但是没有值
(b) set 可变,但是frozenset 不可变(如其名)
一个非常大的不同之处:Perl 中赋值号默认的行为是拷贝,但是Python 中赋值号会创建一个对象的引用。
另外,因为和弱类型的Perl 不同,Python 是一门强类型语言,所以也有判断对象类型的必要。
下面代码演示了这些区别,首先是一段Python 代码
下面是与之完全等价的Perl 代码,对比一下你就会很快了解其中的差别
上下文的判断几乎已经成了一名Perl 用户不可或缺的第六感,一个显而易见的例子是当你定义一个列表
当你循环遍历的时候,你深知把for 循环
替换为While 循环
究竟会得到什么灾难性的后果。
但是在Python 中你不必担心这个:Python 对于数据类型的解释很明确,不会因为上下文环境不同而改变,当你定义一个列表
之后,你永远不必担心在什么特殊的上下文中lst 会被Python 解释为数值3。
Perl 和Python 的面向对象给人的感觉是后者明显比前者更加规范,下面是自己感受最明显的几点异同。
a. 真的是面向对象么?
1). Perl 中的“面向对象”更像是“面向过程”的文字游戏:类通过包实现、方法通过包中定义的函数实现、类的继承和方法的重载通过@ISA 列表查找循序实现、私有方法通过指向匿名函数的my 引用实现(因为my变量是本文件可见的)、运算符重载通过指向函数的引用实现、对象中成员变量的访问通过bless 到类名的引用实现……这样如果说有好处,那就是编程可以非常灵活——你可以用一个父类的多个子类共同继承出一个类(例如从哺乳动物中人类和猫类继承出一种新生物),Perl 完全对这种行为不在意,只要你确信这种近亲结婚的方式真的是你需要达到的目的。当然坏处显而易见——你可以轻而易举把代码写的糟糕透顶。所以Perl 的“面向对象”给人的感觉只是“面向过程”的另一种玩法——面向过程的本质没变,但是面向对象的效果达到了。
2). Python 中的“面向对象”比Perl 要严谨和规范许多,非常类似于Java,如果你熟悉Java 或者C++,那么你会很好理解Python 的面向对象编程。
b. 包和类
1). Perl 中两者完全等价,一个包就是一个类(pm 是Perl 模块的意思,但是它又被叫做包,而包就是类的意思 ← ←)。
2). Python 中一个包可以包含多个模块,一个模块可以包含多个类。
c. 静态方法
Perl 和Python 中静态方法都是第一个参数不是类的引用的方法,但是稍有不同:
1). Perl 中静态方法第一个参数是类名,可以通过bless 新的引用到类名来操作对象类型(例如你在构造方法里做的那样)。
2). Python 中静态方法完全无法操作对象类型。
d. 私有方法:
1). Perl 中的私有方法通过my 变量只有当前文件可见的性质,用保存匿名函数的my 引用来达到“私有”的目的(“面向对象”的文字游戏)。
2). Python 中吧以“__”开头的方法都当作私有方法,通过方法名会变成"_类名__方法名" 的形式来避免其他类调用该方法,但是你仍然可以通过手动变换后的方法名直接调用私有方法。
e. 方法的传参:
1). Perl 中一般将散列的引用bless 到类名,所以传参可以十分灵活,如果构造函数允许,参数个数和位置根本无关紧要,但是随之造成的问题就是可能引发混乱。
2). Python 中方法声明无法把无默认值的参数放在有默认值的参数后面,但是因为实参可以通过给出参数名手动显式指定,所以次序也可以无关紧要。
f. 运算符重载:
1). Perl 通过use overload 模块指定方法的引用来达到重载运算符的目的。
2). Python 中通过一组特殊名称的方法来重载运算符。
g. 父类方法重载:
1). Perl 中通过@ISA 列表的搜索顺序来达到重载父类方法的目的(子类的同名方法会被优先搜索到),并且可以显式SUPER 伪类访问被覆盖的基类方法(就如你经常在析构方法中做的一样)。
2). Python 的重载更加正式,形式非常类似于C++。
h. 继承:
1). Perl 的继承只是操作了@ISA 列表,子类中没有的方法会在@ISA 中寻找方法名,因此这种行为得到的结果和面向对象编程的继承相同。UNIVERSAL 是所有类的祖先类,提供了isa 方法用来测试继承关系。
2). Python 的继承类似于C++,显式指定了要继承的父类,object 类是所有类的祖先类,提供issubclass 方法用来测试继承关系。
下面的两个例子都会有相同的输出,演示了Perl 和Python 中类的构造、析构、公有方法、私有方法、运算符重载、继承、父类方法重载等。
下面是预期的输出
--------------------------------------------------------
下面是你熟悉的Perl
--------------------------------------------------------
下面是完全等价的Python
转载自:http://blog.csdn.net/iSpeller/article/details/23198211
标签:
原文地址:http://www.cnblogs.com/sky-heaven/p/5888889.html