Perl 和 Python 的比较 【转】

转自: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 "@_\[email protected]\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 有一个大致的了解 _(:з)∠)_

基本数据类型

1. Perl 中的标量

a. Perl 中的标量在Python 中对应为数字类型和字符串类型

Perl 的标量是字符串还是数值会根据上下文自动判断,但是Python 不会这样做。

下面的代码是你在Perl 中习以为常的操作

[plain] view plaincopy

  1. my ($string, $number) = ("1", );
  2. $number = $string + "1";  # $string 和"1" 都被解释为数值
  3. say $number;
  4. $string = $number.1;      # $number 和1 都被解释为字符串
  5. say $string;

但是Python 中你必须显式的指定数据类型

[python] view plaincopy

  1. string = "1"
  2. number = int (string) + 1     # 必须显式转换为数值类型
  3. print (number)
  4. string = str (number) + "1"   # 同样必须显式转换为字符串
  5. print (string)

b. Perl 的标量不支持下标运算,但是Python 的字符串可以

Python 中你可以很方便的用下标索引字符串(而且和Perl 中的列表一样也支持用负数做反向索引)

[python] view plaincopy

  1. s = "A string"
  2. print (s[2:])

但是Perl 的标量就无法这样操作,相同的操作必须用列表切片完成

[plain] view plaincopy

  1. $_ = "A string";
  2. say ((split //)[2..split //]);

c. Perl 中的heredoc 式标量赋值在Python 中可以使用三引号运算符完成

[plain] view plaincopy

  1. @_ = <<end;  < span="" style="word-wrap: break-word;">
  2. Everthing is
  3. in
  4. the array
  5. END
  6. say "@_";

下面是等价的Python 代码,注意第一行是紧跟三引号运算符之后的

[python] view plaincopy

  1. string = ‘‘‘‘‘Everthing is
  2. in
  3. the array
  4. ‘‘‘
  5. print (string)

2. Perl 中的列表

a. Perl 中的列表Python 中对应为列表和元组

下面是Python 中倒序排序一个列表的操作

[python] view plaincopy

  1. my_list = ["Hello", "Python"]
  2. my_list.append ("World")
  3. my_list += ["!"]
  4. print (my_list)
  5. my_list.sort ();
  6. my_list.reverse ();
  7. for string in my_list:
  8. print (string)

对应的Perl 同性质操作的版本

[plain] view plaincopy

  1. @_ = qw/Hello Perl/;
  2. push @_, ‘World‘;
  3. @_ = (@_, ‘!‘);
  4. print "@_\n";
  5. @_ = reverse sort @_;
  6. say for @_;

b. 常用的splice 操作在Python 中可以用过index () 方法和del 操作完成

下面是Perl 中常用的splice 操作

[plain] view plaincopy

  1. @_ = qw/Hello Perl !/;
  2. splice @_, 2, 0, "World";       # 插入元素
  3. say "@_";
  4. my @removed = splice @_, 1, 2;  # 提取一段元素并在原列表删除
  5. print "@_\[email protected]\n";

Python 中对应的操作

[python] view plaincopy

  1. my_list = ["Hello", "Python", "!"]
  2. my_list.insert (2, "World") # 插入元素
  3. print (my_list)
  4. removed = my_list[1:2]      # 提取一段元素
  5. del my_list[1:2]            # 并在原列表删除
  6. print (my_list)
  7. print (removed)

注意:Python 中元组和列表的区别

元组创建后是只读的,但是列表随时都可以被修改。

3. Perl 中的哈希

a. Perl 中的哈希Python 中对应为字典和集合

一个Perl 哈希按照键值升序遍历的操作如下

[plain] view plaincopy

  1. my %hash = (
  2. "first" => 1,
  3. "second" => 2,
  4. "third" => 3
  5. );
  6. say "$_ => $hash{$_}" for sort keys %hash;

Python 中代码如下(注意定义变为花括号)

[python] view plaincopy

  1. my_hash = {
  2. "first" : 1,
  3. "second" : 2,
  4. "third" : 3
  5. }
  6. items =  sorted (my_hash.items (), key=lambda e:e[1], reverse=False)
  7. for item in items:
  8. print (item[0], ‘:‘, item[1])

注意:Python 中集合与字典的不同之处

(a) 仅包含键,但是没有值

(b) set 可变,但是frozenset 不可变(如其名)

4. Python 强类型的判断和赋值

一个非常大的不同之处:Perl 中赋值号默认的行为是拷贝,但是Python 中赋值号会创建一个对象的引用。

另外,因为和弱类型的Perl 不同,Python 是一门强类型语言,所以也有判断对象类型的必要。

下面代码演示了这些区别,首先是一段Python 代码

[python] view plaincopy

  1. lst = [1, 2, 3]
  2. lst2 = lst                  # lst2 是lst 的一个引用
  3. print (lst)
  4. lst2[1] = 2.5               # 所以修改lst2 也会引起lst 的变化
  5. print (lst)
  6. lst3 = copy.deepcopy (lst)  # lst3 是lst 的一个深拷贝
  7. lst3[1] = 2
  8. print (lst)                 # 修改lst3 不会引起lst 的变化
  9. # 因为Python 是强类型语言,所以需要类型判断操作
  10. if lst == lst2:                 # 如果s 和s2 值相同
  11. print ("lst equal to lst2")
  12. if lst is lst2:                 # 如果s 和s2 是指向同一个对象的引用
  13. print ("lst and lst2 is the same")
  14. if type (lst) is type (lst3):   # 如果s 和s3 类型相同
  15. print ("lst and lst3 has same type")

下面是与之完全等价的Perl 代码,对比一下你就会很快了解其中的差别

[plain] view plaincopy

  1. my @lst = (1..3);
  2. my $lst2 = \@lst;   # lst2 是lst 的一个引用
  3. say "@$lst2";
  4. $lst2->[1] = 2.5;   # 所以修改lst2 也会引起lst 的变化
  5. say "@$lst2";
  6. my @lst3 = @lst;    # lst3 是lst 的一个深拷贝
  7. $lst3[1] = 2;
  8. say "@lst";         # 修改lst3 不会引起lst 的变化
  9. =pod
  10. 因为Perl 是弱类型语言,所以不需要类型判断操作
  11. 但是Perl 中仍然可以做这样的操作——虽然没什么意义
  12. =cut
  13. say "lst equal to lst2"
  14. if @lst == @$lst2;          # 如果s 和s2 值相同
  15. say "lst and lst2 is the same"
  16. if \@lst == $lst2;          # 如果s 和s2 是指向同一个对象的引用
  17. say "lst and lst3 has same type"
  18. if ref \@lst eq ref \@lst3; # 如果s 和s3 类型相同

5. Perl 中的“上下文”

上下文的判断几乎已经成了一名Perl 用户不可或缺的第六感,一个显而易见的例子是当你定义一个列表

[plain] view plaincopy

  1. my @lst = (1..3);

当你循环遍历的时候,你深知把for 循环

[plain] view plaincopy

  1. say for @lst;   # 列表上下文

替换为While 循环

[plain] view plaincopy

  1. say while @lst; # 标量上下文

究竟会得到什么灾难性的后果。

但是在Python 中你不必担心这个:Python 对于数据类型的解释很明确,不会因为上下文环境不同而改变,当你定义一个列表

[python] view plaincopy

  1. 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

  1. =My name‘s Lucy, 2 years old. Adoption me please.
  2. +I am hungry offen.
  3. -My name‘s Leia, 1 years old. My host is iSpeller.
  4. +I hate milk but my host give me offen.
  5. -My name‘s Lucy, 2 years old. My host is iSpeller.
  6. +I hate milk but my host give me offen.

--------------------------------------------------------

下面是你熟悉的Perl

[plain] view plaincopy

  1. #!/usr/bin/perl
  2. # ========================
  3. # filename: main.pm
  4. # main 类,演示了:
  5. # 类的实例化
  6. # =======================
  7. package main;
  8. use warnings;
  9. use strict;
  10. use 5.010;
  11. use Dog;
  12. use Pet_Dog;
  13. push @INC, ‘.‘;
  14. # 一条叫Lucy 的汪星人
  15. my $lucy = Dog->new (name => ‘Lucy‘, age => 2);
  16. $lucy->say_hello;
  17. $lucy->my_secret;
  18. # 第一条宠物汪,默认为1 岁的leia
  19. my $pet_leia = Pet_Dog->new (host => ‘iSpeller‘);
  20. $pet_leia->say_hello;
  21. $pet_leia->my_secret;
  22. # 纳入第二个宠物汪
  23. # 调用了Pet 类运算符重载函数
  24. my $pet_lucy = $lucy + "iSpeller";
  25. $pet_lucy->say_hello;
  26. $pet_lucy->my_secret;
  27. 1;

[plain] view plaincopy

  1. # ========================
  2. # filename: Dog.pm
  3. # Pet 类,演示了:
  4. # 构造、析构方法
  5. # 公有、私有方法
  6. # 重载
  7. # ========================
  8. package Dog;
  9. use strict;
  10. use warnings;
  11. use 5.010;
  12. use overload ‘+‘ => \&meet;   # 重载加号运算符
  13. # 构造方法
  14. # 是静态方法,第一个参数为类名
  15. sub new {
  16. my $type = shift;
  17. my $class = ref $type || $type;
  18. # 如有用户实例变量则覆盖默认属性
  19. my $self = { name => ‘Leia‘, age => 1, is_pet => 0, @_ };
  20. bless $self, $class;
  21. return $self;
  22. }
  23. # 析构方法
  24. # 是虚方法,第一个参数为类的引用
  25. sub DESTROY {
  26. my $self = shift;
  27. # 调用父类析构方法
  28. $self->SUPER::DESTROY
  29. if $self->can (‘SUPER::DESTROY‘);
  30. }
  31. # 公有方法
  32. sub say_hello {
  33. my $self = shift;
  34. print ‘=‘
  35. if $self->isa ("UNIVERSAL");  # UNIVERSAL 类是所有类的祖先类
  36. printf "My name‘s %s, %d years old. %s.\n",
  37. $self->{name}, $self->{age},
  38. $self->{is_pet}
  39. ? "I am a pet dot"
  40. : "Adoption me please";
  41. }
  42. # 私有方法
  43. my $say_secret = sub {
  44. my $self = shift;
  45. say ‘+‘, $self->{is_pet}
  46. ? "I hate milk but my host give me offen."
  47. : "I am hungry offen.";
  48. };
  49. # 私有方法只能在本文件内由其他方法访问(my $say_secret)
  50. sub my_secret {
  51. my $self = shift;
  52. $self->$say_secret;
  53. }
  54. # 重载加号运算符,返回成为宠物后的自身
  55. sub meet {
  56. my $self = shift;
  57. my @property = %$self;
  58. my $new = Pet_Dog->new (@property, host => shift);
  59. return $new;
  60. }
  61. 1;

[plain] view plaincopy

  1. # ========================
  2. # filename: Pet_Dog.pm
  3. # Pet_Dog 类,继承自Dog 类,演示了:
  4. # 继承、父类方法的重载
  5. # =======================
  6. package Pet_Dog;
  7. use strict;
  8. use warnings;
  9. use 5.010;
  10. use base qw/Dog/;  # 继承自Dog 类
  11. sub new {
  12. # 调用父类的构造方法
  13. # 因为shift 得到的是子类的类名,所以不需要重新bless
  14. my $self = Dog::new (shift, host => "none", @_, is_pet => 1);
  15. return $self;
  16. }
  17. # 重载父类的say_hello (虚)方法
  18. sub say_hello {
  19. my $self = shift;
  20. print ‘-‘
  21. if $self->isa ("Dog");   # 继承关系测试
  22. printf "My name‘s %s, %d years old. My host is %s.\n",
  23. $self->{name}, $self->{age}, $self->{host};
  24. }
  25. 1;

--------------------------------------------------------

下面是完全等价的Python

[python] view plaincopy

  1. #!/usr/bin/python3
  2. # filename: main.py
  3. # ========================
  4. # Dog 类,演示了:
  5. # 构造、析构方法
  6. # 公有、私有方法
  7. # 重载
  8. # ========================
  9. class Dog:
  10. # 构造方法
  11. # 是私有方法,因为方法名以"__" 开头
  12. def __init__ (self, name = "Leia", age = 1, is_pet = 0):
  13. # 如有用户实例变量则覆盖默认属性
  14. self.name = name
  15. self.age = age
  16. self.is_pet = is_pet
  17. # 析构方法
  18. # 静态方法,不会操作实例类型
  19. # 类似Perl,第一个参数不是引用,所以你无法通过第一个参数来引用实例变量
  20. @staticmethod
  21. def __del__ ():
  22. pass
  23. # 公有方法
  24. def say_hello (self):
  25. if issubclass (Dog, object):
  26. print ("=", end=‘‘)
  27. print ("My name‘s %s, %d years old. %s."
  28. % (self.name, self.age,
  29. # Python 中没有三目运算符,可以用下面的形式替代
  30. "I am a pet dog"
  31. if self.is_pet
  32. else "Adoption me please"))
  33. # 私有方法
  34. def __say_secret (self):
  35. print ("+%s."
  36. % ("I hate milk but my host give me offen"
  37. if self.is_pet
  38. else "I am hungry offen"))
  39. # 私有方法只能在本类内由其他方法访问
  40. def my_secret (self):
  41. self.__say_secret ()
  42. # 重载加号运算符为和对方恋爱,返回成为女朋友后的自身
  43. def __add__ (self, other):
  44. new = Pet_Dog (self.name, self.age, 1, other)
  45. return (new)
  46. # ========================
  47. # Pet_Dog 类,继承自Dog 类,演示了:
  48. # 继承、父类方法的重载
  49. # ========================
  50. class Pet_Dog (Dog):
  51. # 调用父类的构造方法
  52. # 之后初始化子类变量
  53. def __init__ (self, name = "Leia", age = 1, is_pet = 1, host = "none"):
  54. Dog.__init__ (self, name, age, is_pet)
  55. self.host = host
  56. # 重载父类的say_hello (虚)方法
  57. def say_hello (self):
  58. if issubclass (Pet_Dog, Dog):
  59. print ("-", end=‘‘)
  60. print ("My name‘s %s, %d years old. My host is %s."
  61. % (self.name, self.age, self.host))
  62. ‘‘‘‘‘
  63. 程序开始,Python 的类型不允许在定义之前使用
  64. 然而Python 似乎又不区分声明和定义
  65. 演示了类的实例化
  66. ‘‘‘
  67. # 一条叫Lucy 的汪星人
  68. lucy = Dog ("Lucy", 2)
  69. lucy.say_hello ()
  70. lucy.my_secret ()
  71. # 第一条宠物汪,默认为1 岁的leia
  72. pet_dog_leia = Pet_Dog (host = "iSpeller");
  73. pet_dog_leia.say_hello ()
  74. pet_dog_leia.my_secret ()
  75. # 纳入第二宠物汪
  76. # 调用了Pet 类运算符重载函数
  77. pet_dog_lucy = lucy + "iSpeller"
  78. pet_dog_lucy.say_hello ()
  79. pet_dog_lucy.my_secret ()

转载自:http://blog.csdn.net/iSpeller/article/details/23198211

时间: 2024-11-05 06:26:14

Perl 和 Python 的比较 【转】的相关文章

关于CGI:Tomcat、PHP、Perl、Python和FastCGI之间的关系

如前文所述,Web服务器是一个很简单的东西,并不负责动态网页的构建,只能转发静态网页.同时Apache也说,他能支持perl,生成动态网页.这个支持perl,其实是apache越位了,做了一件额外的事情. 现在我们看生成动态网页这件事情. CGI的定义是:外部应用程序与Web服务器之间的接口. 明白了吧?也就是说,所谓的动态网页,都是要外部应用程序生成的,而不是Web服务器能干的事情.所以,最初的.最简单的CGI,是使用C来写的,很简单. 到了后来,大家觉得老用C也不是个办法啊,效率这么慢,老板

编程语言的选择(perl和python)-我的一点心得

相信有很多人初学编程的人会在语言选择困难症.说白了,我认为大多数人都害怕自己选择的语言会被淘汰或者使用不广泛,今天我就来谈谈关于编程语言选择的那点事. 我想拿perl和python来举例说明,因为这两门语言的关系就跟java和c++一样,perl阵营和python阵营都各自有各自的理由. 语言的选择和操作系统的选择很类似,有的人爱用linux有的人爱用windows,至于说到底是linux好还是windows好,谁也说不清.在日常工作中,windows无疑有巨大优势,但是在专业领域,linux反

Perl和Python的比较(主要是性能比较)

Python语法简单,而且通过缩进的方式来表现层次结构,代码非常简明易懂,对初学者来说,比较容易上手. Perl的模式匹配非常强大,同时匹配的符号有很多种,难以阅读和维护. 在文本处理方面,python通过加载re模块来实现模式匹配的查找和替换.而Perl内置就有模式匹配功能. note:内置命令和外部命令的区别. 通过代码来直接做比较. python版: #!/usr/bin/python import re import fileinput exists_re = re.compile(r'

按固定元素数目分割数组- perl,python

要求:把40个元素的数组,按每行8个,分5行打印出来.如下图 1 2 3 4 5 6 7 89 10 11 12 13 14 15 1617 18 19 20 21 22 23 2425 26 27 28 29 30 31 3233 34 35 36 37 38 39 40 起因:遇到一些处理数据文件的场景,比如每8行求一次平均值,最大值,或者别的什么操作,可以先抽象为每8行打印到一个数组里,然后直接对该数组处理 1 #!/usr/bin/perl -w 2 use strict; 3 4 my

在notepad++中运行perl和python的方法

1.打开notepa++按F5 在对话框中输入cmd /k C:\Strawberry\perl\bin\perl.exe "$(FULL_CURRENT_PATH)" & ECHO. & PAUSE & EXIT 保存之后 运行2,cmd /k C:\Program File(x86)\python\...(python运行程序文件路径) "$(FULL_CURRENT_PATH)" & ECHO. & PAUSE &

shell perl python 剖析

先不用说"无论什么语言都是一种工具".工具是我们身体的一部分,解放军解放台湾靠"小米加***"? "工具无所谓"论可以休矣.对于实际的软件工程工具和平台的选择是很重要的,有时候是致命的1. perl是强大的, perl=shell+awk+sed+一堆命令行工具.   但是反过来也一样shell+awk+sed+一堆命令行工具可以替代perl. 2. shell的简约,可读性比perl好,工具之间通过命令行stdio管道通信,任何一个小部分都可以

Emacs编辑器之Python与Perl的IDE环境配置

链接:http://pan.baidu.com/s/1c0fjY3e 密码:j8pe 网盘里的文件为我的配置文件,及所使用的lisp源码包.下载后,可以解压到用户家目录即可. 我的Emacs配置文件内容为: # cat ~/.emacs ;; 禁用开机启动画面 (setq inhibit-startup-message t) ;; 默认tab为4个宽度 (setq-default tab-width 4) (setq fill-column 70) ;; 显示设置 (display-time-m

比较Perl、PHP、Python、Java和Ruby

!预览 · 语言的发展趋势一定是动静结合.刚柔并济 · Perl凝练晦涩,Python优雅明晰,Ruby精巧灵动,PHP简明单纯 · 或许优雅正是来自对细节和规范的重视 · (RoR)与Ruby结合之后,便如一只猱身而上灵猫,立刻衬托出Java和.NET大象般的身影 ?提问 Perl.Python.Ruby和PHP各自有何特点? 为什么动态语言多作为轻量级的解决方案? LAMP为什么受欢迎? Ruby on Rails为什么会流行? 编程语言的发展趋势是什么? :讲解 “剩下四种动态语言,我们将

JSP,PHP,Python,Ruby,Perl概要及各自特点

JSP,PHP,Python,Ruby,Perl概要及各自特点 博客分类: JSP PHP Python Ruby Perl概要及各自特点 javascript 互联网技术日新月异,编程的语言层出不穷,原本稍微平静了几年的网络编程技术又不断出现新的东西,涤荡着整个网络世界,ruby,Python等技术使我 们原本比较老板的编程理念和概念产生了混淆和动荡.他们有什么区别和联系?怎么定义这些新生的事物?抹去额头因为生疏而津津的汗滴,从头Google一下 吧.