Python to Perl Conversions
Tom Christiansen
tchrist at mox.perl.com
Thu Aug 19 11:21:55 EDT 1999
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 at jpl-devvax.JPL.NASA.GOV>
More information about the Python-list
mailing list