Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Lexical scope: converting Perl to Python

11 views
Skip to first unread message

Andrew Savige

unread,
Jun 13, 2009, 1:02:53 AM6/13/09
to pytho...@python.org

I'd like to convert the following Perl code to Python:

 use strict;
 {
   my %private_hash = ( A=>42, B=>69 );
   sub public_fn {
     my $param = shift;
     return $private_hash{$param};
   }
 }
 print public_fn("A");        # good:  prints 42
 my $x = $private_hash{"A"};  # error: good, hash not in scope

The real code is more complex; the above is a simplified example.

Notice that this code uses Perl's lexical scope to hide the
%private_hash variable, but not the public_fn() function.

While I could convert this code to the following Python code:

 private_hash = dict( A=42, B=69 )
 def public_fn(param):
   return private_hash[param]
 print public_fn("A")     # good:  prints 42
 x = private_hash["A"]    # works: oops, hash is in scope

I'm not happy with that because I'd like to limit the scope of the
private_hash variable so that it is known only inside public_fn.

Of course, I could hide the hash like so:

 def public_fn(param):
   private_hash = dict( A=42, B=69 )
   return private_hash[param]

yet I'm not happy with that either because of the repeated
initialization the hash each time the function is called.

What is the Pythonic equivalent of Perl's lexical scope, as
illustrated by the code snippet above?

Thanks,
/-\

Need a Holiday? Win a $10,000 Holiday of your choice. Enter now.http://us.lrd.yahoo.com/_ylc=X3oDMTJxN2x2ZmNpBF9zAzIwMjM2MTY2MTMEdG1fZG1lY2gDVGV4dCBMaW5rBHRtX2xuawNVMTEwMzk3NwR0bV9uZXQDWWFob28hBHRtX3BvcwN0YWdsaW5lBHRtX3BwdHkDYXVueg--/SIG=14600t3ni/**http%3A//au.rd.yahoo.com/mail/tagline/creativeholidays/*http%3A//au.docs.yahoo.com/homepageset/%3Fp1=other%26p2=au%26p3=mailtagline

Terry Reedy

unread,
Jun 13, 2009, 1:43:29 AM6/13/09
to pytho...@python.org
Andrew Savige wrote:
> I'd like to convert the following Perl code to Python:
>
> use strict;
> {
> my %private_hash = ( A=>42, B=>69 );
> sub public_fn {
> my $param = shift;
> return $private_hash{$param};
> }
> }
> print public_fn("A"); # good: prints 42
> my $x = $private_hash{"A"}; # error: good, hash not in scope
>
> The real code is more complex; the above is a simplified example.
>
> Notice that this code uses Perl's lexical scope to hide the
> %private_hash variable, but not the public_fn() function.
>
> While I could convert this code to the following Python code:
>
> private_hash = dict( A=42, B=69 )
> def public_fn(param):
> return private_hash[param]
> print public_fn("A") # good: prints 42
> x = private_hash["A"] # works: oops, hash is in scope

Why would you do that if you do not want to do that?

> I'm not happy with that because I'd like to limit the scope of the
> private_hash variable so that it is known only inside public_fn.

def public_fn():


private_hash = dict( A=42, B=69 )
def public_fn(param):
return private_hash[param]

return public_fn
public_fn = public_fn()
print (public_fn("A"))
x = private_hash["A"]

# outputs
42
Traceback (most recent call last):
File "C:\Programs\Python31\misc\t1", line 8, in <module>
x = private_hash["A"]
NameError: name 'private_hash' is not defined

Terry Jan Reedy

Mike Kazantsev

unread,
Jun 13, 2009, 1:44:31 AM6/13/09
to
On Fri, 12 Jun 2009 22:02:53 -0700 (PDT)
Andrew Savige <ajsa...@yahoo.com.au> wrote:

> I'd like to convert the following Perl code to Python:
>
>  use strict;
>  {
>    my %private_hash = ( A=>42, B=>69 );
>    sub public_fn {
>      my $param = shift;
>      return $private_hash{$param};
>    }
>  }
>  print public_fn("A");        # good:  prints 42
>  my $x = $private_hash{"A"};  # error: good, hash not in scope
>

...


>
> What is the Pythonic equivalent of Perl's lexical scope, as
> illustrated by the code snippet above?

If you're using scope for garbage-collecting purposes, there's "with"
statement and contextlib:

from contextlib import contextmanager

@contextmanager
def get_hash():
complex_hash = dict(A=42, B-69)
try: yield complex_hash
except Exception as ex:
del complex_hash # complex destructor ;)
raise ex

with get_hash() as hash:
# do stuff with hash

Note that this only makes sense if you need to implement some complex
operation on hash destruction, and do that whatever-happens-inside-with
to close the object, obviously not the case with simple dict above.

And if you want to obfuscate one part of your code from another, you'll
probably have better luck with languages like java, since no one seem
to care about such stuff with python, so it'd be a hack against the
language, at best.
Why would you want to hide the code from itself, anyway? It's not like
you'd be able to accomplish it - code can easily grep it's process body
in memory and harvest all the "private" values, so I'd suggest getting
some fresh air when you start to feel like doing that.

--
Mike Kazantsev // fraggod.net

signature.asc

jenifer adam

unread,
Jun 13, 2009, 4:42:38 AM6/13/09
to
>  signature.asc
> < 1KViewDownload

Check http://www.voipsipsdk.com its a good one.

I V

unread,
Jun 13, 2009, 7:48:28 AM6/13/09
to
On Fri, 12 Jun 2009 22:02:53 -0700, Andrew Savige wrote:
> Notice that this code uses Perl's lexical scope to hide the
> %private_hash variable, but not the public_fn() function.

You might try:

def public_fn(param):
private_hash = publicfn.private_hash
return private_hash[param]

public_fn.private_hash = {'A':42, 'B':69}

(You don't have to assign public_fn.private_hash to a local variable, but
you might want to, to avoid extra typing, if you refer to private_hash
more than a couple of times in the function).

Nick Craig-Wood

unread,
Jun 13, 2009, 8:29:35 AM6/13/09
to

Either

_private_hash = dict( A=42, B=69)

def public_fn(param):
return _private_hash[param]

Or

def public_fn(param, _private_hash = dict( A=42, B=69)):
return _private_hash[param]

Is probably the pythonic equivalents. Note that private_hash starts
with an underscore which means it won't be exported from a module by
default and it is a convention that it is private and shouldn't be
fiddled with. I'd probably go with the latter of the two examples.

--
Nick Craig-Wood <ni...@craig-wood.com> -- http://www.craig-wood.com/nick

John S

unread,
Jun 13, 2009, 4:11:46 PM6/13/09
to
On Jun 13, 8:29 am, Nick Craig-Wood <n...@craig-wood.com> wrote:
> Nick Craig-Wood <n...@craig-wood.com> --http://www.craig-wood.com/nick

Another approach is to just use a class to hold the data, and a class
method (AKA classmethod) to access the data:

# class definition
class my_util(object):
_private_hash = { 'A':42,'B':69 }

@classmethod
def public_fn(cls,index):
return cls._private_hash[index]

# usage
print my_util.public_fn('A')
print my_util.public_fn('B')

This keeps pretty close to the OP's intention. It does require you to
use the class name, but that's.....OK, and better than an anonymous
block IMHO.

Note: I'm a recovering Perl hacker.

Rhodri James

unread,
Jun 13, 2009, 4:58:10 PM6/13/09
to pytho...@python.org
On Sat, 13 Jun 2009 06:02:53 +0100, Andrew Savige <ajsa...@yahoo.com.au>
wrote:

> What is the Pythonic equivalent of Perl's lexical scope, as
> illustrated by the code snippet above?

The useful (to you) pythonic answer depends rather a lot on
why you want to do something like that. While you've been
given several possibilities, the "correct" answer might well
be "don't do that at all" :-)

--
Rhodri James *-* Wildebeest Herder to the Masses

0 new messages