Perl traps for Python Programmers

I'm updating the Camel. Chapter 24 has short sections for people moving from one language to the next. Right now I'm working on the Python section. My Python is rusty. If you started in Python and moved to Perl, I'd like to hear about the gotchas that you didn't expect.

This is absolutely not a platform for bashing another language. I don't care about any of that. I don't care why the readers want to use Perl or why they want to use Python. I care about people who are used to doing something one way in Python and might be surprised why that's not obvious or apparent in Perl.

Here's some things I have so far, which I just cut from our own pseudopod:

=head1 Python Traps XXX: Still might not be in the book

Perl and Python come from common roots, and even came out at the same time
(1987 and 1991), and Perl even stole Python's object system.

=for TODO
http://wiki.python.org/moin/PerlPhrasebook

=over 4

=item *

X<variables;Perl vs. Python, names of>
Variables begin with C<$>, C<@>, or C<%> in Perl.

=item *

Many functions take default arguments or have default behavior. See
A<29>.

=item *

The last-evaluated expression is the return value.

=item *

Perl's

=item *

Use C<say> if you want an implicit newline on the end of each
output.

=item *

Perl has object features, but it is not an object-oriented language
where everything has methods.

In Perl, you call a function with arguments:

my $string = join('|', qw(Python Perl Ruby) );

In Python, there's likely a main argument with a method to do it:

new = '|'.join(['Python', 'Perl', 'Ruby'])

=item *

Perl's match operator floats unless you anchor your patten. Python's
C<re.match()> only matches at the beginning of a line, although
C<re.search()> has an implicit C<.*> at the beginning of the pattern.

=item *

XXX: Python's dictionaries are Perl's hashes

=item *

In most cases, Perl does not implicitly dereference things (although
Perl 5.12 does for some uses of the array and hash operators).

=item *

Perl can interpolate variable directly into double-quoted strings,
but you can use C<sprintf>

=item *

Perl's strings aren't arrays of characters, so you can't use array
operators on them.

=item *

Perl's system calls don't automatically throw exceptions, but you
can use M<autodie> to do that.

=item *

Python lets you name your arguments in the function signature. In
Perl you have to do that yourself:

sub R<METHOD> {
my ($self, @args) = @_;
}

=item *

Perl doesn't have lists of lists, but it can have a list of array
references.

=item *

Perl's range operator is inclusive on both sides, so C<0..9> includes C<0> and C<9>.

=item *

To overload operators for your objects, use the M<overload> pragma.

=back


7 Comments

Things I've noticed from my coworkers who were new to perl from python background:

* they want to use subroutine signatures, and they don't work the way they expect. (Mainly because they don't work the way anyone expects them)

* python has +=, but doesn't have ++ (is that really true? I read it on hyperpolyglot). in python += doesn't return a value, so can't be chained.

* couple this with confusion/disregard of auto-vivification they won't write this loop:

for my $item ( @list ) { $count{ $item }++ }

instead writing:
for my $item (@list)
{
if ( !exists $count{$item} )
{
$count{$item} = 0
}
$count{$item}=$count{$item} + 1
}

in perl any method can be an object constructor, not just __init__

One of the things I use a lot in Perl is closures that capture outer lexicals, and mutate them. I.e.

my $counter = 0;
my $incsub = sub { $counter++ };

which is something new, that has no direct Python equivalent.

@Paul In Python we have nested functions/lambda functions. Technically, they are different functions but they have closure of environment.

i = 0
j = (lambda (i):i+1)(i)

@Deepak: Yes there are nested functions and lambdas with closures, but what you posted is not the same at all. The simplest near equivalent to what Paul posted that I can come up with is:

def mkcntr():
  def _cnt():
    _cnt.cnt += 1
    return _cnt.cnt
  _cnt.cnt = -1
  return _cnt
f=mkcntr()
print f()
print f()

I guess the more general issue of the closure example above is really different variable scoping rules. Those ought to be a potential source of confusion there. Python has some odd rules IMHO to its function scope and seems scattered with workarounds like global/nonlocal, whereas Perl not only has functions as first-class citizens, but has some (again, IMHO) more sane scoping rules.

Another possible source of confusion might be the Perl release policy and its pragmas. In Perl-land you have to explicitly ask for new/better/saner/nowadays behaviour, as by default you get (very/excessive || superb, depending on the job) strict backwards compatibility.
use strict/warnings/autodie/feature/mro/etc are all lexically scoped (again, the scope :D) with more on CPAN, eg: no autovivification
That's why when you see "modern" Perl code it usually starts off with half-a-page of "use pragma" lines :)) (come to think of it, perldoc perlpragma, import/unimport, hints hash, compile-time, there are actually quite a few concepts stuffed inside a "use pragma" line :/)

Then the REPL. I know Python folks are much more used to working with a REPL then we are and will probably be expecting a "builtin" one. Either the debugger or something like Devel::REPL ?

Smaller standard library. LWP/URI are not "builtins". Neither are xml/event-libs/datetime/logging/exceptions/whatnot modules. A perlbrew+cpanm setup would be recommended nowadays.

There are many other differences of course, these are just a few I can remember from my chats with some Python folks. HTH.

@runrig You're right about my code. I must admit I am not very good at reading perl code :)

Leave a comment

About brian d foy

user-pic I'm the author of Mastering Perl, and the co-author of Learning Perl (6th Edition), Intermediate Perl, Programming Perl (4th Edition) and Effective Perl Programming (2nd Edition).