(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)
| [reply] [d/l] [select] |
|
|
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.
| [reply] [d/l] [select] |
|
|
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)
| [reply] [d/l] [select] |
|
|
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.
| [reply] [d/l] [select] |
|
|
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)
| [reply] [d/l] [select] |
|
|
|
|
| [reply] |
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 :
- 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)
- 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)
- 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
- 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
| [reply] [d/l] |
|
|
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
| [reply] [d/l] |
|
|
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
| [reply] [d/l] |
|
|
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 :). | [reply] [d/l] |
|
|
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
| [reply] [d/l] |
|
|
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).
| [reply] [d/l] [select] |
|
|
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. :)
| [reply] [d/l] |