Lexical scope: converting Perl to Python

A

Andrew Savige

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=X3oDMT...om/homepageset/?p1=other&p2=au&p3=mailtagline
 
M

Mike Kazantsev

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

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.11 (GNU/Linux)

iEYEARECAAYFAkozPMMACgkQASbOZpzyXnFS3wCcCDe8US2lWnJy8+Lh0urWpVR6
JKkAnjCamHwKsEgKzEpx3sKDKFh55qWm
=46R7
-----END PGP SIGNATURE-----
 
J

jenifer adam

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
< 1KViewDownload

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

John S

Andrew Savige said:
 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?

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.

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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,048
Latest member
verona

Latest Threads

Top