Does anyone know of any tools or have any experience converting Python to Perl? I'm having particular problems converting Python code working with tuples to Perl, and converting complex data structures like Hashes of Arrays of Hashes to Python (from what I can see Perl kills Python here). I've done several searches on the subject but haven't found much. Any advice, tools, or references on the subject are very welcome. Thanks in advance.

  • Comment on Converting Python to Perl and back again

Replies are listed 'Best First'.
(jeffa) Re: Converting Python to Perl and back again
by jeffa (Bishop) on Apr 04, 2003 at 06:21 UTC
    Well, what particular problems? What particular piece of Python code? I can tell you one thing for sure, any code that converts Python to Perl is broken at best. There probably will not be any such tool that is worthy until a Python binding for Parrot is completed.

    I can say that a Python tuple is analogous to a Perl list, not a Perl array (a Python list is what we Perl folk call an array). As for converting complex data structures ... well ... Perl is not really that much different from Python, at least it doesn't have to be:

    Python:

    thingy = [ { 'artist' : 'Genesis', 'genre' : ['pop','rock','progressive'], 'albums' : [ { 'title' : 'Foxtrot', 'year' : 1972 }, { 'title' : 'Duke', 'year' : 1980 }, { 'title' : 'Genesis', 'year' : 1983 }, ], }, ]

    Perl:

    $thingy = [ { artist => 'Genesis', genre => [qw(pop rock progressive)], albums => [ { title => 'Foxtrot', year => 1972 }, { title => 'Duke', year => 1980 }, { title => 'Genesis', year => 1983 }, ], }, ];
    We can help you convert Python code to Perl, but i doubt you'll get much help from us converting Perl code to Python. ;)

    jeffa

    L-LL-L--L-LL-L--L-LL-L--
    -R--R-RR-R--R-RR-R--R-RR
    B--B--B--B--B--B--B--B--
    H---H---H---H---H---H---
    (the triplet paradiddle with high-hat)
    

      Hi, thanks for the reply. Sorry I didn't provide examples of the code but the powers that be won't let me you see (they try to shut me down on MTV.. heh, sorry). Your example helped a lot though, and I have most of it done. Just two more questions with regards to the data structures, could you let me know how close these are:

      name = thingy['albums'][0]['title'] $name = $thingy{albums}[0]{title}

      Should both return 'Foxtrot' (without the quotes), correct?

      And as for populating the structures, could I do something such as the following:

      thingy['artistName'][0]['year'] = 1987 or thingy{'artistName}[0]{'year'} = 1987

      And if I did it this way, how would I go about populating multiple entries in the album field, would I have to use a counter, or is there some other way? Thanks again.

        Your first snippet is close, but thingy is a an array/list, not a hash/dictionary, so you need to index the very first item in that array/list, which is a hash/dictionary:
        name = thingy[0]['albums'][0]['title'] my $name = $thingy->[0]{albums}[0]{title};
        For your second snippet, you will need to loop through each hash/dictionary that is contained inside the 'album' array/list:
        for a in thingy[0]['albums'] : a['year'] = 1999 $_->{year} = 1999 for @{$thingy->[0]->{albums}};
        As you can see, you don't need a counter, you only need to process each element at a time. Perl and Python are both good about giving the coder 'ease of iteration'. ;)

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        

      Okay, I've got another fine Python question for you wise Perlmonks (well, know thy enemy, right? ;-). Say I want data such as:

      genesis = { "Foxtrot":({"instrumental":"Okay"}, {"vocals":"Good"}), "D +uke":({"vocals":"Better"}) }

      How would I go about initially populating the dictionary? Say, as if I was reading from a database and looping over it. There isn't an insert or append operator for dictionaries, and I can't seem to just go: genesis["Foxtrot"]["instrumental"] = "Okay" Any ideas? Thanks.

        That's right, what you have is illegal syntax in either language. You are trying to access a HoH (hash of hashes) instead of what you really have, a LoH (list of hashes). You simply are missing the array index:
        genesis['Foxtrot'][0]['instrumental'] = 'excellent' $gensis->{Foxtrot}[0]{instrumental} = 'excellent';
        Now then, as for populating these datastructures from a database ... well, i can't help you much with Python. You'll have to read the docs, but i can say that Perl's DBI has methods that will form these datastructures for you, methods such as:
        • selectall_arrayref
        • selectall_hashref
        • fetchrow_arrayref
        • fetchrow_hashref
        and more. I usually only use selectall_arrayref, but sometimes i need the lookup power of hashes. You have to ensure that all of your data has unique id's in order for hashes to work safely (without clobbering existing keys). Recently i decided to roll my own:
        # takes prepared statement handle and returns LoH sub db2tmpl { my ($sth) = @_; $sth->execute; my $fields = $sth->{NAME}; my $rows = $sth->fetchall_arrayref; my @loh; for my $row (@$rows) { my %hash; @hash{@$fields} = @$row; push @loh, {%hash}; } return \@loh; }
        This is very useful with HTML::Template, though i can't help but feel i am re-inventing a wheel. At any rate, i wish you the best of luck. :)

        jeffa

        L-LL-L--L-LL-L--L-LL-L--
        -R--R-RR-R--R-RR-R--R-RR
        B--B--B--B--B--B--B--B--
        H---H---H---H---H---H---
        (the triplet paradiddle with high-hat)
        

      Thanks for all the help, I think I've got it now :)

Re: Converting Python to Perl and back again
by Corion (Patriarch) on Apr 04, 2003 at 06:42 UTC

    Converting between Python and Perl is not easily done by simple subsitutions, as there are some strong differences between how Python variables and Perl variables work :

    1. A Python tuple is immutable - you can't change any part of it - this makes it hard(er) to represent a tuple in Perl with the same semantics (I think of a tied Array as a solution)
    2. Python dictionaries take tuples (and not strings) as keys - this makes Perl hashes hard to use for that area, as you have to find a way to encode any tuple to a string and back (I think of URLencoding the tuples and a special marker for the different elements of the tuple)
    3. Python knows no explicit references, in fact, everything in Python is a reference - this is not that bad, as Perl also dosen't know complex data structures without references, but in Perl, those references are explicit
    4. Python can easily do deep comparision of data, where with Perl you will have to manually recurse through the data - this makes some algorithms nastier to read under Perl

    perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web
      Actually, Perl hashes take lists as keys too. This is essential for Regexp::Common's API. Behind the scene, Perl joins the list using $; as the join string to turn the list into a string.

      Abigail

        I know, but to make this work in a general fashion when converting Python code to Perl code, you need to make sure that no list element can stringify to something containing $; - it's possible but not quite simple (that's what I wanted to say when I mentioned URLencoding). Of course simply storing a (stringified) reference to a static array (which implements a tuple) would also work, but then you're on the way of reimplementing Python in Perl - a slippery slope.
        For general consumption, there also is Hash::MultiKey, which allows one to use (general) lists (or rather, references to those) as hash keys, presumably in the same way, by storing a stringified list reference as the hash key.

        perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web

      Good points. With regard to number 4, is there an alternative in Perl for something such as

      a = [1, 2, 3] b = [1, 2, 4] if (a < b): print "a is less than b"

      Or would I end up recursing through the array, comparing each element individually?

      I should note that I've never found this useful, so I won't hold it against Perl if it doesn't have this feature :).

        There is no straightforward way in Perl, no. The way I go in Perl is most of the time using the is_deeply method from Test::More, but you end up doing the recursion manually. In Python, I've used this thing a lot in reporting sorted arrays - it's very convenient, but this is impossible under the current Perl due to the way sort works. Once could override sort to do the Right Thing whenever it encounters two arrays of references and no block is passed to it, but I don't know at what cost - and most code dosen't use that anyway.

        perl -MHTTP::Daemon -MHTTP::Response -MLWP::Simple -e ' ; # The $d = new HTTP::Daemon and fork and getprint $d->url and exit;#spider ($c = $d->accept())->get_request(); $c->send_response( new #in the HTTP::Response(200,$_,$_,qq(Just another Perl hacker\n))); ' # web

        Actualy, there is a way, though it's somwhat odd. Instead of using lists, use version-strings. In recent (>5.6, IIRC) versions of perl, v1.2.3 eq chr(1).chr(2).chr(3) (the v is optional if there are more then two elements, but be warned that there is a (fairly large) size limit on the elements), so what you're doing there is equivlent to

        $a = v1.2.3; $b = v1.2.4; if ($a lt $b) { print "a is less than b"; }


        Warning: Unless otherwise stated, code is untested. Do not use without understanding. Code is posted in the hopes it is useful, but without warranty. All copyrights are relinquished into the public domain unless otherwise stated. I am not an angel. I am capable of error, and err on a fairly regular basis. If I made a mistake, please let me know (such as by replying to this node).

      2. Python dictionaries take tuples (and not strings) as keys - this makes Perl hashes hard to use for that area, as you have to find a way to encode any tuple to a string and back (I think of URLencoding the tuples and a special marker for the different elements of the tuple)

      Well, no. :)

      The values of dictionary keys in Python can be any immutable object, including strings and tuples that contain no mutable elements (e.g. a tuple that contains a list as one of its elements could not be a key).

      As yet another challenge to add to the list; sigils. $foo, @foo and %foo semantics can't be represented in Python.

      Python has built-in support for iterators and generators; Perl does not. There's no reasonable conversion path for these semantics.

      Python classes can inherit from built-in types. The complications of munging this into some funky tie-fu aren't worth the return on investment (especially when you consider that Python's built-ins are a lot different from Perl's built-ins).

      The best way to convert Python to Perl and Perl to Python is to contribute to the development of Parrot because there are far too many issues to make it reasonable to truly "convert" one to the other.

      It's like trying to "convert" a BMW M5 into a Ferrari 360 Modena. I'll let you decide which is which. :)