zoukankan      html  css  js  c++  java
  • 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 "@_
    ";  
    @_ = 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 "@_
    @removed
    ";  
    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.
    ",  
              $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.
    ",  
              $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在CODE上查看代码片派生到我的代码片
     
    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在CODE上查看代码片派生到我的代码片
     
    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在CODE上查看代码片派生到我的代码片
     
    1. s = "A string"  
    2. print (s[2:])  

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

     

     

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. $_ = "A string";  
    2. say ((split //)[2..split //]);  

     

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

     

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. @_ = <<end;  < span="" style="word-wrap: break-word;">
    2. Everthing is  
    3.     in  
    4.       
    5. the array  
    6. END  
    7. say "@_";  

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

     

     

    [python] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. string = '''''Everthing is 
    2.     in 
    3.      
    4. the array 
    5. '''  
    6. print (string)  

     

    2. Perl 中的列表

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

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

     

    [python] view plaincopy在CODE上查看代码片派生到我的代码片
     
    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在CODE上查看代码片派生到我的代码片
     
    1. @_ = qw/Hello Perl/;  
    2. push @_, 'World';  
    3. @_ = (@_, '!');  
    4. print "@_ ";  
    5. @_ = reverse sort @_;  
    6. say for @_;  

     

     

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

    下面是Perl 中常用的splice 操作

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. @_ = qw/Hello Perl !/;  
    2. splice @_, 2, 0, "World";       # 插入元素  
    3. say "@_";  
    4. my @removed = splice @_, 1, 2;  # 提取一段元素并在原列表删除  
    5. print "@_ @removed ";  

    Python 中对应的操作

     

     

    [python] view plaincopy在CODE上查看代码片派生到我的代码片
     
    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在CODE上查看代码片派生到我的代码片
     
    1. my %hash = (  
    2.   "first" => 1,  
    3.   "second" => 2,  
    4.   "third" => 3  
    5. );  
    6. say "$_ => $hash{$_}" for sort keys %hash;  

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

     

     

    [python] view plaincopy在CODE上查看代码片派生到我的代码片
     
    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在CODE上查看代码片派生到我的代码片
     
    1. lst = [123]  
    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.   
    10. # 因为Python 是强类型语言,所以需要类型判断操作  
    11. if lst == lst2:                 # 如果s 和s2 值相同  
    12.   print ("lst equal to lst2")  
    13. if lst is lst2:                 # 如果s 和s2 是指向同一个对象的引用  
    14.   print ("lst and lst2 is the same")  
    15. if type (lst) is type (lst3):   # 如果s 和s3 类型相同  
    16.   print ("lst and lst3 has same type")  

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

     

     

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
    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.   
    10. =pod  
    11. 因为Perl 是弱类型语言,所以不需要类型判断操作  
    12. 但是Perl 中仍然可以做这样的操作——虽然没什么意义  
    13. =cut  
    14. say "lst equal to lst2"  
    15.   if @lst == @$lst2;          # 如果s 和s2 值相同  
    16. say "lst and lst2 is the same"  
    17.   if @lst == $lst2;          # 如果s 和s2 是指向同一个对象的引用  
    18. say "lst and lst3 has same type"  
    19.   if ref @lst eq ref @lst3; # 如果s 和s3 类型相同  

     

    5. Perl 中的“上下文”

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

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. my @lst = (1..3);  

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

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. say for @lst;   # 列表上下文  

    替换为While 循环

    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. say while @lst; # 标量上下文  

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

     

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

    [python] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. lst = [123]  

    之后,你永远不必担心在什么特殊的上下文中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上查看代码片派生到我的代码片
     
    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在CODE上查看代码片派生到我的代码片
     
    1. #!/usr/bin/perl  
    2.   
    3. # ========================  
    4. # filename: main.pm  
    5. # main 类,演示了:  
    6. # 类的实例化  
    7. # =======================  
    8.   
    9. package main;  
    10. use warnings;  
    11. use strict;  
    12. use 5.010;  
    13. use Dog;  
    14. use Pet_Dog;  
    15.   
    16. push @INC, '.';  
    17.   
    18. # 一条叫Lucy 的汪星人  
    19. my $lucy = Dog->new (name => 'Lucy', age => 2);  
    20. $lucy->say_hello;  
    21. $lucy->my_secret;  
    22.   
    23. # 第一条宠物汪,默认为1 岁的leia  
    24. my $pet_leia = Pet_Dog->new (host => 'iSpeller');  
    25. $pet_leia->say_hello;  
    26. $pet_leia->my_secret;  
    27.   
    28. # 纳入第二个宠物汪  
    29. # 调用了Pet 类运算符重载函数  
    30. my $pet_lucy = $lucy + "iSpeller";  
    31. $pet_lucy->say_hello;  
    32. $pet_lucy->my_secret;  
    33.   
    34. 1;  
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. # ========================  
    2. # filename: Dog.pm  
    3. # Pet 类,演示了:  
    4. # 构造、析构方法  
    5. # 公有、私有方法  
    6. # 重载  
    7. # ========================  
    8.   
    9. package Dog;  
    10. use strict;  
    11. use warnings;  
    12. use 5.010;  
    13.   
    14. use overload '+' => &meet;   # 重载加号运算符  
    15.   
    16. # 构造方法  
    17. # 是静态方法,第一个参数为类名  
    18. sub new {  
    19.   my $type = shift;  
    20.   my $class = ref $type || $type;  
    21.   
    22.   # 如有用户实例变量则覆盖默认属性  
    23.   my $self = { name => 'Leia', age => 1, is_pet => 0, @_ };  
    24.   bless $self, $class;  
    25.   return $self;  
    26. }  
    27.   
    28. # 析构方法  
    29. # 是虚方法,第一个参数为类的引用  
    30. sub DESTROY {  
    31.   my $self = shift;  
    32.   
    33.   # 调用父类析构方法  
    34.   $self->SUPER::DESTROY  
    35.     if $self->can ('SUPER::DESTROY');  
    36. }  
    37.   
    38. # 公有方法  
    39. sub say_hello {  
    40.   my $self = shift;  
    41.   
    42.   print '='  
    43.     if $self->isa ("UNIVERSAL");  # UNIVERSAL 类是所有类的祖先类  
    44.   
    45.   printf "My name's %s, %d years old. %s. ",  
    46.           $self->{name}, $self->{age},  
    47.           $self->{is_pet}  
    48.             ? "I am a pet dot"  
    49.             : "Adoption me please";  
    50. }  
    51.   
    52. # 私有方法  
    53. my $say_secret = sub {  
    54.   my $self = shift;  
    55.   
    56.   say '+', $self->{is_pet}  
    57.         ? "I hate milk but my host give me offen."  
    58.         : "I am hungry offen.";  
    59. };  
    60.   
    61. # 私有方法只能在本文件内由其他方法访问(my $say_secret)  
    62. sub my_secret {  
    63.   my $self = shift;  
    64.   $self->$say_secret;  
    65. }  
    66.   
    67. # 重载加号运算符,返回成为宠物后的自身  
    68. sub meet {  
    69.   my $self = shift;  
    70.   my @property = %$self;  
    71.   my $new = Pet_Dog->new (@property, host => shift);  
    72.   return $new;  
    73. }  
    74.   
    75. 1;  
    [plain] view plaincopy在CODE上查看代码片派生到我的代码片
     
    1. # ========================  
    2. # filename: Pet_Dog.pm  
    3. # Pet_Dog 类,继承自Dog 类,演示了:  
    4. # 继承、父类方法的重载  
    5. # =======================  
    6.   
    7. package Pet_Dog;  
    8. use strict;  
    9. use warnings;  
    10. use 5.010;  
    11.   
    12. use base qw/Dog/;  # 继承自Dog 类  
    13.   
    14. sub new {  
    15.   # 调用父类的构造方法  
    16.   # 因为shift 得到的是子类的类名,所以不需要重新bless  
    17.   my $self = Dog::new (shift, host => "none", @_, is_pet => 1);  
    18.   return $self;  
    19. }  
    20.   
    21. # 重载父类的say_hello (虚)方法  
    22. sub say_hello {  
    23.   my $self = shift;  
    24.   print '-'  
    25.     if $self->isa ("Dog");   # 继承关系测试  
    26.   
    27.   printf "My name's %s, %d years old. My host is %s. ",  
    28.           $self->{name}, $self->{age}, $self->{host};  
    29. }  
    30.   
    31. 1;  



     

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

    下面是完全等价的Python

     

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


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

  • 相关阅读:
    NSURLSession 网络请求
    NSData 数据
    NSStream文件流
    NSFileManager文件管理
    NSCache 缓存
    NSUserDefaults数据存储
    NSKeyedArchiver数据归档
    子线程定时器的创建
    NSEnumerator迭代器
    NSDate 时间
  • 原文地址:https://www.cnblogs.com/sky-heaven/p/5888889.html
Copyright © 2011-2022 走看看