`
kingwmj
  • 浏览: 1187 次
  • 性别: Icon_minigender_1
  • 来自: 天津
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

perl,python和ruby的对比

阅读更多
perl,python和ruby的对比 (2012-05-19 11:00:13)[编辑][删除]转载▼
标签: it
看到这篇文章挺好,所以转来,以防将来找不到了.
转:http://danvk.org/josephus.html

The Josephus Problem
What is the Josephus problem? To quote from Concepts, Techniques, and Models of Computer Programming (a daunting title if ever there was one):
Flavius Josephus was a roman historian of Jewish origin. During the Jewish-Roman wars of the first century AD, he was in a cave with fellow soldiers, 40 men in all, surrounded by enemy Roman troops. They decided to commit suicide by standing in a ring and counting off each third man. Each man so designated was to commit suicide...Josephus, not wanting to die, managed to place himself in the position of the last survivor.
In the general version of the problem, there are n soldiers numbered from 1 to n and each k-th soldier will be eliminated. The count starts from the first soldier. What is the number of the last survivor?
I decided to model this situation using objects in three different scripting languages, Perl, Ruby, and Python. The solution in each of the languages is similar. A Person class is defined, which knows whether it is alive or dead, who the next person in the circle is, and what position number it is in. There are methods to pass along a kill signal, and to create a chain of people. Either of these could have been implemented using iteration, but I wanted to give recursion a whirl, since it's tougher on the languages. Here are my results.

Perl
package Person;
use overload q("") => \&to_s;

# Create a new, living Person with the given position
sub new {
    my $invocant = shift;
    my $class = ref($invocant) || $invocant;
    my $pos = shift;
    my $self = { "position" => $pos,
                 "alive" => 1,
                 "succ" => undef };
    return bless($self,$class);
}

# Getter/Setter for successor
sub succ : lvalue {
    my $self = shift;
    $self->{succ}
}

# Create a chain of people
sub createChain {
    my $self = shift;
    my $n = shift;
    return $self unless $n;
    
    my $succ = Person->new($self->{position}+1);
    $self->succ = $succ;
    $succ->createChain($n-1)
}

# Pass on the killing message
sub circularKill {
    my $self = shift;
    my ($pos,$nth,$remaining)=@_;

    return $self->{succ}->circularKill($pos, $nth, $remaining)
        unless $self->{alive};
    return $self unless $remaining > 1;
    
    if ($pos == $nth) {
        $self->{alive} = 0;
        $pos = 0;
        $remaining--;
    }
    $self->{succ}->circularKill($pos+1, $nth, $remaining)
}

# Print descriptive information
sub to_s{ 
    my $self = shift;
    "Person #".$self->{position}.", ".($self->{alive} ? "alive" : "dead")
}

# Circle of $n people, kill every one out of every $m
$m = 3;
$n = 40;

$first = new Person(1);
$last = $first->createChain($n-1);
$last->succ = $first;

$winner = $first->circularKill(1,$m,$n);
print "Winner: ", $winner, "\n";



What's good:
Support for statement modifiers (ie, the 'if' or 'unless' after a line
Last evaluated expression is assumed to be the return value (look at sub succ)
Once the class is actually defined, everything seems fairly clean
It runs, quickly, and gets the right answer
What's bad:
It looks ugly as hell, and feels like a hack. Look at the new routine! Without the help of Programming Perl (aka The Camel), I would have been clueless how to write this.
Also under the "it's a hack" heading, I don't like how each subroutine begins by shifting $self off of the arguments stack. This seems unnatural.
Overloading the "stringification" operator was a little roundabout (look at the use overload line. Again, this felt unnatural, and I wouldn't have had a clue how to do it without The Camel.

So, in conclusion, defining classes in Perl is decidedly inelegant, and unintuitive. If I were to do it often, I'd have to cut and paste that new routine wherever I went. That's a BIG stumbling block, and it would probably be enough to keep me from using OO in Perl. In fact, it has been for the past several years.
I wanted to do some OO however, so I checked out Python and Ruby. Here's the same problem coded using each of them.
Ruby
class Person
    attr_reader :position, :succ, :alive
    attr_writer :position, :succ, :alive
    
    # Everyone is alive, initially
    def initialize(pos)
        @position = pos
        @alive = true
    end
    
    # For creating a linked chain of people
    def createChain(n)
        return self unless n>0
        @succ = Person.new(@position + 1)
        @succ.createChain(n-1)
    end
    
    # Kill every nth person
    # Current position in the cycle is pos
    # there are remaining people remaining
    # Stop killing if we're the last one.
    def kill(pos,nth,remaining)
        return @succ.kill(pos,nth,remaining) if !@alive
        return self if (remaining == 1)
        
        if pos == nth
            @alive = false
            puts self
            pos = 0
            remaining-=1
        end
        @succ.kill(pos+1,nth,remaining)
    end
    
    # Information about this person
    def to_s
        "Person \##@position, #{@alive ? 'alive' : 'dead'}"
    end
end

# Set n to anything much higher (like 10, say)
# And the program hangs, or has an "Illegal Instruction"
n = 7

first = Person.new(1)
last  = first.createChain(n-1)
last.succ = first

winner = first.kill(1,3,n)
# If I use puts "Winner: " + winner, I get an error:
#    in `+': failed to convert Person into String (TypeError)
#puts "Winner: " + winner
puts "Winner: ", winner


What's good:
Since this was my first Ruby script, I can't claim to have written good, idiomatic code, but it sure looks nice to me. It's far more elegant than the Perl mess, and significantly shorter as well.
I like the attr_reader and attr_writer shortcuts.
"stringification" overloading was pretty simple, especially since this is done frequently in the online reference.
As in Perl, there are statement modifiers and the last statement is the return value, a fact which I used in most of these routines.
I like the flexible interpolation via #{}
What's bad:
While the code looks great, the execution sucks. Ruby's limit on stack depth seems to be set somewhere around 60, which is absurdly low. This clearly prevents setting n particularly high. While n=40 worked in both Perl and Python, Ruby gives an "Illegal Instruction" error or just hangs, which I eventually figured out was its way of saying that the depth limit had been reached. There may be some way around it, but this limitation seems pretty atrocious.
When there's an error in a Ruby program, the error messages tend to be pretty useless, usually along the lines of "There's an error in line x", if that. When I had n set at 40, I'd just get an "Illegal Instruction" error, which was incredibly misleading. Setting the --debug flag didn't help in this department.
Also, and I may just be missing something here, puts "Winner: " + winner told me that it couldn't convert a Person into a String, which it clearly could, since puts winner worked fine.

So in conclusion, I really liked coding in Ruby, but the execution just wasn't there. If there are any Ruby fans out there who know how to fix the problems I mentioned, I'd be thrilled to hear from you.
Python
class Person:
    def __init__(self,pos):
        self.pos = pos
        self.alive = 1
    def __str__(self):
        return "Person #%d, %s" % (self.pos, self.alive)
    
    # Creates a chain of linked people
    # Returns the last one in the chain
    def createChain(self,n):
        if n>0:
            self.succ = Person(self.pos+1)
            return self.succ.createChain(n-1)
        else:
            return self

    # Kills in a circle, getting every nth living person
    # When there is only one remaining, the lone survivor is returned
    def kill(self,pos,nth,remaining):
        if self.alive == 0: return self.succ.kill(pos,nth,remaining)
        if remaining == 1: return self
        if pos == nth:
            self.alive = 0
            pos=0
            remaining-=1
        return self.succ.kill(pos+1,nth,remaining)

# n people in a circle
# kill every mth person
n = 40
m = 3

first = Person(1)
last = first.createChain(n-1)
last.succ = first

print "In a circle of %d people, killing number %d" % (n,m)
winner = first.kill(1,m,n)
print "Winner: ", winner


What's good:
It's very compact (shortest of the three), mostly because of the lack of lines to end blocks (ie, "end" in Ruby or "}" in Perl). Not having these lines does feel a little weird, but I think I could get used to it.
I like the printf-style formatting via the % operator. I can't say whether I like it more than the direct interpolation in Ruby and Perl, however.
Unlike in Ruby, the program ran without a hitch, and got the right answer.
What's bad:
__init__ and __str__? This seems ugly, though that may be part of the "never touch anything starting with __" credo coming in from my C background.
Passing self as the first parameter of every routine makes Python's OO seem almost as hackish as Perl's or PHP's. I much prefer Ruby's system of using @ to indicate an instance variable, rather than "self.".
I wish I could use tabs instead of four spaces to indicate indentation.
No statement modifiers, and there has to be an explicit return statement. These aren't major drawbacks, but I'd rather have them than not.
Python isn't quite as clean as Ruby, though it certainly trounces Perl. It would be hard not to trounce Perl. The performance was much better than in Ruby, however: Python ran the script for n=40 without any hitches. In the debugging department, syntax errors included helpful information, including where in the line the error occured.
Now for the comparison. First of all, I'll throw Perl right out. I love the language, but not for object-oriented programming. To write a purely procedural program I'd take it over both Ruby and Python any day of the week, but not for OO.
If I had my choice in the matter, I would use Ruby. It's syntax seems cleaner, and it's object orientation doesn't seem hackish in the least. It's performance, however, left a lot to be desired. Granted, deep recursion probably isn't the most widely used technique, but there's no reason it shouldn't work. For a different sort of problem, I'd likely choose Ruby, though I'm worried I might have to switch over to Python if I ran into similar problems.
And that brings us to the aforementioned beast. It seems to present the middle ground in this problem. It's syntax is fairly clean though, as I mentioned, I'd rather not have to type "self." all the time. But on the plus side, it could actually solve the problem without crashing.
So for this round, the winner is Python, though I really wish it had been Ruby. For most problems, I'll go with Ruby. It's more enjoyable to code in, and that's what I'm coding for--enjoyment.
分享到:
评论

相关推荐

    为什么你一定要学习Python或Ruby语言.pdf

    尽管Perl曾是动态语言的首选,但现在已被Python和Ruby取代。Perl的面向对象机制复杂,学习曲线陡峭,而Python和Ruby则提供了更直观、更简洁的语法。对于需要大量正则表达式处理的特殊场景,Perl仍有其优势,但对于...

    python和ruby,我选谁?

    - **可移植性**:相较于Perl等其他脚本语言,Python和Ruby拥有更好的跨平台兼容性。 - **图形界面编辑器**:虽然Python的编辑器选择更多样化,Ruby也有专门的图形界面编辑器。 - **库支持**:它们都有大量的库可供...

    每个程序员都应该学习使用Python或Ruby

    Perl语言虽然在Python和Ruby之前就已经是重要的动态语言,但现在Perl已经开始衰落,取而代之的是Python和Ruby。Perl虽然面向对象性设计显得不够完整,并且其语法在易读性方面被认为有诸多不足,这使得它对于学生来说...

    python-ruby-golang:比较python,ruby和golang

    python-ruby-golang click(Python),thor(Ruby)和cli.go(Golang)的比较,用于构建非常简单的命令行工具。 快速开始 有关更多信息,请参见每个子目录中的README.md。 博客文章

    最好用的Lua,Python,Perl,Ruby,NSIS开发编辑器

    - 多语言支持:同时支持Lua、Python、Perl、Ruby和NSIS的语法高亮、代码提示和格式化。 - 调试功能:内置或集成调试器,允许开发者对各语言进行断点调试。 - 项目管理:支持多项目,方便切换和组织不同语言的代码。 ...

    SWIG 公开 C/C++ 代码,包括 Ruby、Perl、Tcl、C# 和 Python

    C 和 C++ 被公认为...SWIG 允许您向广泛的脚本语言公开 C/C++ 代码,包括 Ruby、Perl、Tcl 和 Python。本文使用 Ruby 作为公开 C/C++ 功能的首选脚本接口。要理解本文,您必须具备 C/C++ 与 Ruby 方面的相应知识。

    生产规模的数据中心分析器CC Go Rust Python Java NodeJS PHP Ruby Perl.zip

    这个压缩包文件"生产规模的数据中心分析器CC Go Rust Python Java NodeJS PHP Ruby Perl.zip"包含了多种编程语言实现的数据中心分析器组件,这表明该工具可能支持跨平台和多语言集成。以下是对这些编程语言在数据...

    基于Python的Web技术

    LAMP 是一种流行的 Web 开发平台,由 Linux、Apache、MySQL 和 PHP、Perl、Python 或 Ruby 等脚本语言组成。LAMP 具有开放灵活、开发迅速、部署方便、高可配置、安全可靠、成本低廉等优点,是目前最流行的 Web 开发...

    体验布局和树

    体验布局和树 -- Linux,C,C++,Java,Ajax,XML,perl,php,python,ruby,MySQL,Gnome,KDE,Qt,Gtk,bash,shell,嵌入式,网络,信息安全,操作系统,数据结构,编译原理体验布局和树 -- Linux,C,C++,Java,Ajax,XML,perl,php,...

    完全用Python工作---Harness the power of Python

    Python的优势在于其通用性,它可以替代C、C++、Java、Ruby等语言的部分功能,并在许多方面表现出更高的效率和便利性。例如,C语言需要处理复杂的内存管理和指针操作,而Python通过自动内存管理简化了这一过程;C++的...

    Methods in Medical Informatics: Fundamentals of Healthcare英文

    《医学信息学方法:在Perl、Python和Ruby中的医疗保健编程基础》(以下简称本书)是一本为医疗保健领域的专业人士提供数据处理技能的实用指南。本书强调了通过简单的算法与开源编程语言即可实现对临床和人群健康数据...

    javalist源码-Parse-Functions:从Perl,Python,Ruby,PHP,Java,JavaScript等源代码中提取

    标题 "javalist源码-Parse-Functions" 暗示了一个项目,它可能是从多种编程语言(如Perl、Python、Ruby、PHP、Java、JavaScript)的源代码中提取解析功能的一个工具或库。这个项目可能关注的是如何解析这些语言中的...

    PYTHON参考手册 第4版_修订版

    内容简介 本书是Python编程语言的杰出参考手册,书中详尽讲解了Python核心和...他创办的Dabeaz 公司提供软件开发、培训和咨询服务,专注于Python、Ruby、Perl 等动态编程语言的实际应用。他是Python 软件基金会的会员。

    ruby编程学习笔记及demo

    Ruby 的特性与 Smalltalk、Perl 和 Python 类似。Perl、Python 和 Smalltalk 是脚本语言。Smalltalk 是一个真正的面向对象语言。Ruby,与 Smalltalk 一样,是一个完美的面向对象语言。使用 Ruby 的语法比使用 ...

    ruby-2.5.1.tar.gz

    Ruby 是一种类似于 Python 和 Perl 的服务器端脚本语言。 Ruby 可以用来编写通用网关接口(CGI)脚本。 Ruby 可以被嵌入到超文本标记语言(HTML)。 Ruby 语法简单,这使得新的开发人员能够快速轻松地学习 Ruby。 ...

    网络爬虫-Python和数据分析.pdf

    相比之下,脚本语言如Perl、Python、Java和Ruby更受青睐,特别是对于需要处理大量文本和网页内容的场景。其中,Python由于其简洁的语法、丰富的库支持、跨平台性以及在科学计算、数据分析、可视化等方面的优势,成为...

    kaitai_struct:Kaitai Struct:使用C ++ C#生成二进制数据解析器的说明性语言Java JavaScript Lua Perl PHP Python Ruby

    它的核心理念是提供一种声明性语言,使得开发者可以描述二进制数据的结构,然后自动生成针对多种编程语言的解析代码,包括 C++、C#、Java、JavaScript、Lua、Perl、PHP、Python 和 Ruby。这极大地简化了二进制数据...

    The Perl Programming Language

    除了Perl之外,Python和Ruby也是流行的脚本语言。它们各有特点: - **Python**:以其简洁明了的语法而闻名,非常适合快速开发。 - **Ruby**:以其灵活的语法和强大的元编程能力著称,常用于Web开发。 #### 七、更多...

    程序设计语言的选择问题推荐.pdf

    在服务器端,PHP、Perl、Python、Ruby和JSP等都是常见选择。 6. 数据库编程:VB和Delphi适合数据库应用,而SQL因其广泛的应用面更受青睐。 7. 性能与操作系统结合:C/C++是最佳选择,VC和gcc分别在Windows和Unix-...

    Python参考手册(第4版·修订版).[美]David M.Beazley(带详细书签)

    本书是Python编程语言的杰出参考手册,书中详尽讲解了Python核心和Python库...他创办的Dabeaz 公司提供软件开发、培训和咨询服务,专注于Python、Ruby、Perl 等动态编程语言的实际应用。他是Python 软件基金会的会员。

Global site tag (gtag.js) - Google Analytics