Subject: Python to Perl Conversions
From: tchrist@mox.perl.com (Tom Christiansen)
Date: 19 Aug 1999 08:21:55 -0700
To: python-list@mail.python.org
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>