in-place value modification (was Re: lambda without vars?)

Jeff Pinyan jeffp at crusoe.net
Wed Mar 15 14:02:37 EST 2000


[posted & mailed]

On Mar 15, François Pinard said:

>However, you cannot have the function to modify such variables (that is,
>the value they have outside lambda).

You can, but it is exceptionally difficult, requires a lot of munging and
trickery, and the method is not the same for different cases:

>>> a = [1,2,3]
>>> def app(name,val):
...   tmp = globals()[name]
...   tmp.append(val)
...
>>> app('a',4)
>>> a
[1, 2, 3, 4]

Here's a much more complex example, which replicates chomp(),
Perl-style.  It is not suggested you USE this, but it shows the lengths
one must go to.

def chomp(name,rem="\n"):  # chomp, Perl-style
  import string

  rlen = len(rem)

  pos = string.find(name, "[");
  if pos != -1:
    # dealing with a subscript
    name, subs = name[:pos], name[pos:]
  else:
    subs = ""

  # globalize name, and set tmp to name (or name[subs])
  exec "tmp = globals()[name]" + subs

  if type(tmp) == type(""):
    if tmp[-rlen:] == rem:
      exec "globals()[name]" + subs + " = tmp[:-rlen]"
      return 1
    else:
      return 0

  # otherwise, operate on a list of some sort...
  retval = 0

  if type(tmp) == type([]) or type(tmp) == type(()):
    cp = []
    for obj in tmp:
      if type(obj) == type(""):
        if obj[-rlen:] == rem:
          obj = obj[:-rlen]
          retval = retval + 1
      cp.append(obj)
    if type(tmp) == type(()): cp = tuple(cp)

  elif type(tmp) == type({}):  # only chomp() the VALUE, not the key
    cp = {}
    for obj in tmp.items():
      val = obj[1]
      if type(val) == type(""):
        if val[-rlen:] == rem:
          val = val[:-rlen]
          retval = retval + 1
      cp[obj[0]] = val

  else: raise TypeError, "expected string, list, tuple, or dict"

  exec "globals()[name]" + subs + " = cp"
  return retval

me = ["jeffrey\n"]
print "'" + `me` + "'"
chomp('me')
print "'" + `me` + "'"



It's nasty. :)  I happen to really like Perl's ability to change the
argument list it receives:

  @values = (10, 20, 30);
  for (@value) { $_ += 10 }
  print "@values";  # 20 30 40
  add_one(@values);
  print "@values";  # 21 31 41

  sub add_one {
    for (@_) { $_++ }
  }

I find it a little icky that you have to bend over backwards to get such
results in Python (even though I DID get it done...).

-- 
MIDN 4/C PINYAN, NROTCURPI, US Naval Reserve             japhy at pobox.com
http://www.pobox.com/~japhy/                  http://pinyaj.stu.rpi.edu/
PerlMonth - An Online Perl Magazine            http://www.perlmonth.com/
The Perl Archive - Articles, Forums, etc.    http://www.perlarchive.com/





More information about the Python-list mailing list