[LWN Logo]

From: Tom Christiansen <tchrist@mox.perl.com>
Subject: Python to Perl Conversions
Date: 19 Aug 1999 08:21:55 -0700

Per your collective requests, here is one of the documents
with my collective observations from learning Python.

Some have mentioned that I've left things out that are in
more recent releases.  I'm sorry, but I only have Mark Lutz's
book to go on.  There are no manpages for Python.   Like most
people, I'll wait until the next edition of the book is release
rather than digging around elsewhere if the manpage are missing.

This article was posted to the Perl newsgroup, but I have duplicated
the posting here without crossposting to avoid flame wars.

--tom

                        +-----------------------+
                        | Operations on numbers |
                        +-----------------------+

Python Construct                Perl Equivalent
===========================================================================
x + y                           + for numbers, . for strings, and
                                interopolation for arrays (@a, @b)
                                and hashes (%a, %b)

x - y                           same

x * y                           * for numbers, x for strings and lists.

x / y                           Same for floats, but Perl doesn't do
                                integer division here usually.  Python
                                things 3/4 is 0 (and false), but 3.0/4.0 is 0.75

x % y                           same; Perl and Python use the same
                                definition of modulus, even though this
                                differs from that of C with respectd to
                                negative operands.

abs(x)                          same

int(x)                          same, except perl only requires it for
                                truncation toward zero, and python
                                needs it all over the place, since
                                strings aren't numbers, nor are they
                                autoconverted.

long(x)                         These are bignums, not C longs, so:
                                    use Math::BigInt;
                                    $n = Math::BigInt->new(expr);

float(x)                        not applicable

divmod(x,y)                     no direct equiv; same as
                                    ( int($x / $y), $x % y )

pow(x,y)                        x ** y

x | y, x ^ y, x & y             same, although python's only work on ints
                                and its bignum longs and blow up
                                on floats, and perl's don't work on
                                Math::BigInts, but do work on strings in
                                a very different way, and truncate floats.

x << n, x >> n                  same, although Perl works differently if
                                you go over 31 bits:  Python keeps giving 
                                you 0, whereas Perl wraps.  1<<34 is 0 in 
                                python but 4 in perl.

~x                              same-ish, but see |&^ above for details.
                                In particular, you can't negate bitstrings
                                in python.

===========================================================================

                            +----------------------------+
                            | Operations on dictionaries |
                            +----------------------------+

Python Construct                Perl Equivalent
===========================================================================

len(d)                          keys %d, in a scalar context; e.g.:
                                    $count = keys %ENV;

d[k]                            "same": $h{$k} as a real %hash, and
                                $hr->{$k} as a reference

d[k] = x                        "same": 
                                    $h{$k} = x;         # real %hash
                                    $href->{$k} = x;    # as reference
                                Note that Python doesn't support hash
                                slices, which in Perl are simple:
                                    @hash{k1,k2,k3} = (v1, v2, v3)

del d[k]                        delete $h{$k}, but Python can't do more
                                than one at a time on a hash, as in Perl's
                                    delete @hash{k1,k2,k3}

d.items()                       Just use %hash in list context to get all
                                the key/value pairs as a flat list.

d.keys()                        keys %hash

d.values()                      values %hash

d.hash_key(k)                   exists $hash{k}

===========================================================================

            +--------------------------------------------------+
            | Operations on sequences (strings, tuples, lists) |
            +--------------------------------------------------+

x in s                          No built-ins, must use grep or loop.
                                    Lists/arrays: grep { $x == $_ } @s
                                    Strings: index($s, $x) != 0

x not in s                      See previous entry.
                                    Lists/arrays: !grep { $x == $_ } @s
                                    Strings: index($s, $x) < 0

for n in x                      for $n (@array)                 # arrays
                                for $c (split //, $string)      # strings

s + s                           $s . $s

s * n, n * s                    $s x $n for strings and lists/arrays, but 
                                must be in that order in Perl.  Python
                                allows the number in either place.

s[i]                            $array[i] for arrays, but
                                substr($s, $i, 1) for strings

s[i:j]                          @array[ $i .. ($j - 1) ]  for arrays, but
                                substr($s, $i, $j - 1) for strings.  Yes, 
                                slices in python don't include the
                                termination point.

len(s)                          @array in a scalar context for arrays, e.g.
                                        $count = @array;
                                but length($s) for strings.

min(s), max(s)                  no equivalent in core perl, so you'd need a
                                loop,  although the CPAN module builtin.pm
                                provides these in fast C code.

===========================================================================

                    +---------------------+
                    | Operations on lists |
                    +---------------------+

s[i] = x                        $a[i] = expr, but Perl can do this even if
                                the array isn't long enough yet, and Python
                                can't.  You have to grow it with the append
                                method below.  

s[i:j] = x                      @a[ i .. (j - 1) = list_expression
                                but see above.  Also, Perl's slices needn't
                                be contiguous, and Python's must.  Yes, slices
                                don't include endpoint in Python.

del s[i]                        splice(@a, i, 1)

del s[i:j]                      splice(@a, i, j - 1) for values of i and j.
                                Yes, slices don't include endpoint in Python.

s.append(x)                     push(@array, listexpr)

s.count(x)                      grep { $_ == expr } @array (for numbers)
                                grep { $_ eq expr } @array (for strings)
                                grep {  /expr/    } @array (for patterns)

s.index(x)                      no direct equivalent, need loop:
                                    $found = undef;
                                    for $i ( 0 .. $#array ) {
                                        if ($array[$i] == expr) { # numeric
                                            $found = $i;
                                            last;
                                        }
                                    } 

s.insert(i,x)                   splice(@array, $i, 0) = x;  

s.remove(x)                     this deletes the first x in s, and has no
                                direct equivalent.  the simple
                                    @a = grep { !/x/ } @a
                                deletes all of them, but as a pattern.  For
                                the first, you'd need a loop or extra
                                variable, because grep doesn't shortcircuit.  
                                    $found = 0;
                                    @a = grep { !/x/ || !$found++) } @a;
                                or as a string
                                    $found = 0;
                                    @a = grep { $_ ne x || !$found++ } @a;

s.reverse                       @a = reverse @a; note that python's reverse
                                is in-place *only*, and doesn't work on
                                character strings.

s.sort(cmp?)                    Noting that Python's sort is in-place only, use
                                    @a = sort @a; 
                                    @a = sort some_cmp @a;


===========================================================================

                            +--------------------+
                            | built-in functions |
                            +--------------------+

apply(fn,args)                  &fn(@args) will skip prototype checks that
                                fn(@args) would normally enforce.  In
                                general, perl doesn't need this at all,
                                because indirect function calls don't do 
                                prototype checks.
                                    $name = "fn";   # or \&fn
                                    $name->(@arglist)

callable(x)                     n/a or else UNIVERSAL::isa($x, "CODE") 

chr(i)                          same

cmp(x,y)                        x cmp y

coerce(x,y)                     n/a!

compile(string,label,kind)      $coderef = eval "sub { $string }"

delattr(object,name)            n/a?  "delete named attribute from object".
                                I suppose this might be
                                        delete $obj->{name}
                                but that's pretty uncool to do it without 
                                asking the object.

dir(object)                     n/a for most.  returns a list of attribute
                                names in object or the caller's local scope.
                                for modules, you can do 
                                        keys %module::
                                and for hash-based objects, 
                                        keys %$obj
                                But you can't get the local (lexical
                                my variables) names in Perl without
                                resorting to C code.

eval(code)                      Same as Perl, but Perl's handles
                                statements, and python's only handles
                                expressions.  Also, python hurls an
                                exception if it doesn't like you,
                                whereas Perl sets $@.  People use this
                                to convert string to numbers.  This is
                                a terrible security hazard.

exec(code)                      eval(code);  plus see previous entry.

execfile(file)                  do 'file';  plus see anteprevious entry.

filter(func,list)               grep { func($_) } list

getattr(obj,name)               n/a?  maybe just $obj->{$name}.  I don't
                                understand why this exits.  Oh heck, yes I
                                do.  Because you can say
                                    name = "widget_count"
                                    obj.name
                                Because there's no interpolation and
                                otherwise it will look up name.  Oh my.
                                This is like the apply() mess.

globals()                       keys %{ __PACKAGE__ . "::" }

hasattr(obj,name)               exists $obj->{$name}

hash(x)                         huh?  "returns the hash value of the object,
                                if any"

hex(n)                          sprintf("%#x", n)
                                Perl's hex() function is the opposite.
                                It converts 22 into 37.  Python's hex
                                function converts 37 into 0x22.  Oh my!

id(obj)                         Just use $obj in numeric context. "returns
                                the unique id for the object, its addr in memory"

input(prompt?)                  n/a.  This reads and evals the input
                                stream!  Needed because otherwise you can't
                                read a number.  Or you could read the
                                string and convert it.  Ick.  Security
                                hazard waiting to happen.

locals()                        n/a.  We can't get our block's lexicals
                                without resorting to C.  And even if
                                we hand them, we can't symbolically
                                dereference they're names, since the
                                package (module's global) symbol table
                                is completely separate from that of the
                                lexicals' (local) one, and sym deref
                                only does the former.

map(fn, list)                   map(fn($_), list) # or written
                                map { fn($_) } list
                                Except Perl's map won't parallelize, as in
                                    map(fn, [1,2,3], [4,5,6])
                                will call fn() thrice, as in
                                        fn(1,4)
                                        fn(2,5)
                                        fn(3,6)
                                Note that Perl's map doesn't have to be
                                function; it can just be a code block.
                                    @trips = map { 3 * $_ } @singles;

oct(n)                          sprintf("%#o", $n)
                                Like hex, Python has this completely
                                backwards.  Python's oct(44) returns 054,
                                but Perl's oct(44) return 36.  UG!

open(path,mode)                 Perl's open function works very differently.
                                    $success = open(FH, mode . path)

ord(c)                          same

range(start?, end, step?)       Either use a range operator, but be careful
                                of the end point:
                                    @nums = $start .. ($end - 1) 
                                or a for() loop
                                    for ($i = $start; $i < $end; $i += $step)
                                or even 
                                    for $i ( $start .. ($end - 1) ) 

raw_input(prompt?)              print "prompt";
                                $line = <STDIN>;
                                chomp($line);    # but perl groks RS

reload(module)                  First delete from %INC, then require the
                                module again, as in:
                                    delete $INC{"Module.pm"}
                                    require Module;
                                Note that Python doesn't directly support
                                nested modules as in
                                    require Dir1::Dir2::Dir3::Module;
                                except via a disgustingly named hackaround
                                module.

repr(x)                         "$x".  Python also use `x` for this.

setattr(obj,name,value)         $obj->{$name} = $value;
                                Interpolation wins again.  See getattr.

str(x)                          I thought this was the same as repr().

tuple(seq)                      n/a.  This is a nasty hack to deal with the
                                fact that (1,2,3) is different from [1,2,3].
                                Hm... maybe it's like this:
                                    $aref = [1,2,3]; 
                                    @list = @$aref;

type(obj)                       ref($obj) returns its string type

vars(obj)                       n/a, maybe.  keys %$obj, but not really
                                anything for the locals.

xrange ...                      Like range, but avoids generating all at
                                once as Python's
                                    for i in range(100000):
                                would.  Perl's solution was to fix 
                                    for $i (1 .. 99999)
                                instead to do lazy evaluation.

===========================================================================

                    +--------------+
                    | file methods |
                    +--------------+

s = file.read(size?)            $bytes_read = read(FH, $s, $size)
                                Perl's read() doesn't let you leave
                                off the last argument to mean "read all".
                                Usually, you undefined your input record
                                separator and use readline for that.

file.readline()                 $s = readline(*FH)
                                    or more commonly
                                $s = <FH>

file.readlines()                @a = readline(*FH)
                                    or more commonly
                                @a = <FH>

file.write(string)              print FH "string"

file.writelines(list)           print FH @array_of_lines

file.close()                    close(FH)

file.tell()                     tell(FH)

file.seek(offset,whence)        seek(FH, offset, whence)

file.isatty()                   -t FH

file.flush()                    Either FH->autoflush(1) if you're using the
                                aliasing modules, or else the klunky but
                                fast:
                                    $old_fh = select(FH);
                                    $| = 1;
                                    select($old_fh);
                                Note that this just sets autoflushing
                                on each subsequent output on that handle.

===========================================================================

    +------------------------------------------------------------+
    | sys library.  There aren't there unless you have imported  |
    | the library module via "import sys".                       |
    +------------------------------------------------------------+

sys.argv                        @ARGV but sys.argv[1] in Python 
                                is $ARGV[0] in Perl, and sys.argv[0]
                                in Python is $0 in Perl, which is mutable.

sys.builtin_module_names        You either recursively go through %main::,
                                or look at %INC.  But these only show what
                                was loaded, not what was built in.

sys.exc_type                    n/a or $@.   Perl doesn't have even
                                loosely typed exceptions, just strings.
                                There is support for exception objects,
                                but people don't use them.

sys.exc_value                   The $@ variable, mostly.  See previous
                                entry.

sys.exc_traceback               n/a or $@.  We have no exception
                                traceback object.  Traceback gets appended
                                to value.

sys.exit(status)                exit(status) and no import is bloody
                                necessary just to leave the program.
                                But that Python does this by raising
                                a SystemExit exception.  Perl can use
                                END{} handlers to catch these and do
                                at-exit processing, and Python doesn't.
                                You have to roll your own.

sys.exitfunc                    This is one function to call on normal exit
                                (not exception exits, unlike perl).
                                It would have to manage all the handlers
                                in your roll-your-own scheme.  Very ugly.

sys.getrefcount(object)         This isn't exposed in Perl, save through the
                                standard Devel::Peek module.

sys.last_type                   n/a.  Type of last unhandled exception.

sys.last_value                  n/a.  Value of last unhandled exception.

sys.last_traceback              n/a.  Traceback of last unhandled
                                exception.

sys.modules                     %INC

sys.path                        @INC

sys.platform                    $^O  # that's a ^ and an O
                                You can use the $OSNAME alias from the
                                std English module if you like.

sys.ps1, sys.ps2                n/a.  interactive prompts.

sys.setcheckinterval(reps)      n/a.  This is some event hook processing
                                thing.

sys.settrace(fn)                n/a. set system traceback function.  I
                                guess you could play with the Carp module.

sys.setprofile                  n/a;  the profiler is separate in perl

sys.stdin                       STDIN

sys.stdout                      STDOUT

sys.stderr                      STDERR

sys.tracebacklimit              n/a

===========================================================================

    +---------------------------------------------------------------+
    | string library.  There aren't there unless you have imported  |
    | the library module via "import string".                       |
    +---------------------------------------------------------------+

string.atof(s)                  n/a - Perl doesn't need this.  Just use
                                the string as a float, and it is one.

string.atoi(s)                  n/a - Perl doesn't need this.  Just use
                                the string as a int, and it is one.

string.atol(s)                  Perl doesn't have built-in bignums.
                                    use Math::BigInt;
                                    $n = Math::BigInt->new($s)

string.expandtabs(s,tabsize)    From a module:
                                use Text::Tabs;
                                $tabstop = 4; 
                                @without_tabs = expand(@with_tabs); 

string.find(s,sub,start?)       index(s,sub,start?)     # no import

string.rfind(s,sub,start?)      rindex(s,sub,start?)    # no import

string.index(s,sub,st)          if (index(s,sub,st) < 0) {die "ValueError"}

string.rindex(s,sub,st)         if (rindex(s,sub,st) < 0) {die "ValueError"}

count(s, sub, start?)           You use a loop or a pattern match:
                                    $count = 0;
                                    $start = 0;
                                    while (($pos=index($s, $sub, $start) >= 0){
                                        $count++;
                                        $start += $pos;
                                    }
                                Or with regex:
                                    @matches = $s =~ /sub/g;
                                    $count = @matches;  # get scalar count
                                Or shorter:
                                    $count = () = $s =~ /sub/g;
                                If you don't want regex magic chars, use
                                    $count = () = $s =~ /\Qsub/g;

string.split(s)                 @a = split(' ', $s)     # no import

string.splitfields(s,sep)       @a = split(/sep/, $s)   # no import
                                If you don't want regex magic chars:
                                @a = split(/\Qsep/, $s) 

string.join(x)                  $s = join(" ", @x);     # no import

string.joinfields(x, sep)       $s = join($sep, @x);    # no import

string.strip(s)                 Use two substs: 
                                    $string =~ s/^\s+//;
                                    $string =~ s/\s+$//;
                                Or combined for legibility and
                                extensibility:
                                    for ($string) {
                                        s/^\s+//;
                                        s/\s+$//;
                                    }

string.swapcase(s)              $s =~ tr[a-zA-Z][A-Za-z]
                                Except this isn't locale-aware.

string.upper(s)                 uc($s)      # no import

string.lower(s)                 lc($s)      # no import

string.ljust(s,width)           sprintf("%*s", -$width, $s)
                                (no import), or use printf(), or use
                                format and write statements.

string.rjust(s,width)           sprintf("%*s", $width, $s)
                                (no import), or use printf(), or use
                                format and write statements.

string.center(s,width)          Easiest with format and write.  Could
                                hack up a (s)printf otherwise.

string.zfill(s,width)           sprintf("%0${width}d", $s)

===========================================================================

        +-------------------------------------------------------------+
        | POSIX library.  These aren't there unless you have imported |
        | the library module via "import posix".                      |
        +-------------------------------------------------------------+

posix.environ                           The %ENV hash; no import needed in Perl.  
                                        However, assignment doesn't appear
                                        to propagate to unborn children as
                                        it does in Perl.

posix.error                             This might be Perl's $! errno
                                        variable, but I'm dubious.
                                        Failed syscalls in python always
                                        raise an exception.

posix.chdir(path)                       chdir(path)     # no import in Perl
                                        Return value is success in Perl --
                                        no exception raised on failure.

posix.chmod(path, mode)                 chmod(path, mode)  # no import in Perl
                                        Return value is success in Perl --
                                        no exception raised on failure.

posix.chown(path,uid,gid)               chown(path,uid,gid) # no import in Perl
                                        Return value is success in Perl --
                                        no exception raised on failure.

posix.close(fd)                         POSIX::close(fd);  # real int, not stdio 
                                        Return value is success in Perl --
                                        no exception raised on failure.

posix.dup(fd)                           POSIX::dup(fd), or just use open as
                                        shown below

posix.dup2(fd, fd2)                     POSIX::dup2(fd, fd2), or just use the
                                        basic open with its funky dup syntax:
                                            open(HANDLE2, "<&$fd")

posix.execv(path,args)                  exec path, args;  # no import in Perl

posix.execve(path,args, env)            Just set your %ENV and then exec().

_exit(n)                                POSIX::_exit(n)

fdopen ....                             Use POSIX::fdopen or funky open:
                                            open(HANDLE2, "<&=$fd")

posix.fork()                            fork()  # no import
                                        Return value is success in Perl --
                                        no exception raised on failure.

posix.fstat()                           stat(HANDLE)    # no import

posix.getcwd()                          use Cwd;  $here = getcwd();
                                        but most folks use `pwd` in perl

posix.getegid                           $)      # not a typo

posix.getpid()                          $$      # not a typo

posix.kill(pid,sig)                     kill(sig,pid)   # no import
                                        In perl, a string is ok
                                            kill("TERM", $$);  # suicide
                                        Or multipids
                                            kill("HUP", $him, $her, @them)
                                        Return value is success in Perl --
                                        no exception raised on failure.

posix.link(src,dst)                     link($src,$dst)  # no import
                                        Return value is success in Perl --
                                        no exception raised on failure.
                                        I'll stop saying this now.

posix.listdir(path)                     opendir(DH, path);
                                        readdir(DH);            # no import

posix.lseek(fd,pos,how)                 seek(HANDLE, pos, how)  # stdio
                                        sysseek(HANDLE, pos, how)  # no stdio
                                        If you only have an fd, use
                                        POSIX::seek() or fdopen it

posix.lstat(path)                       lstat(path)             # no import

mkdir(path,mode)                        mkdir(path,mode)        # no import

open(path,flags,mode)                   sysopen(HANDLE,path,flags,mode)
                                        no import of posix needed except
                                        for flags.  use Fcntl is more
                                        widely supported for this.

(f1,f2) = posix.pipe()                  pipe(FH1, FH2)          # no import

fd = posix.popen(cmd,mod,bufsiz)        No import.  Just use regular open.
                                            open(FH, "| cmd")   # writing
                                            open(FH, "cmd | ")  # reading

posix.read(fd,n)                        POSIX::read or sysread() or usually
                                        just regular read()

posix.readlink(path)                    readline(path)          # no import

posix.rename(src,dst)                   rename(src,dst)         # no import

posix.rmdir(path)                       rmdir(path)             # no import

posix.setgid(id)                        $) = id         # not a typo

posix.stat(path)                        stat(path)      # no import
                                        But if the list return is icky, you
                                        can use the File::stat module to
                                        get by-name object values.

posix.symlink(src,dst)                  symlink(src,dst)    # no import

posix.system(cmd)                       system(cmdstr)      # no import
                                        Perl also a shell-safe version:
                                        system(arglist)

posix.times()                           times()             # no import

posix.umask(mask)                       umask(mask)         # no import

posix.uname()                           POSIX::uname()

posix.unlink(path)                      unlink(path)        # no import
                                        perl also allows a list
                                        unlink(f1,f2,f3)

posix.utime ...                         utime...            # no import

posix.wait()                            wait()              # no import

posix.waitpid(...)                      waitpid(...)        # no import

posix.write(fd,str)                     use syswrite() normally, 
                                        or maybe POSIX::write


===========================================================================
-- 
If you consistently take an antagonistic approach, however, people are
going to start thinking you're from New York.   :-)
        --Larry Wall to Dan Bernstein in <10187@jpl-devvax.JPL.NASA.GOV>