pythonic equivalent of upvar?
Bengt Richter
bokr at oz.net
Tue Dec 20 13:02:40 EST 2005
On Tue, 20 Dec 2005 16:10:30 +0200, mackay at aims.ac.za (David MacKay) wrote:
>Dear Greater Py,
>
><motivation note="reading this bit is optional">
> I am writing a command-line reader for python.
>
> I'm trying to write something with the same brevity
>as perl's one-liner
>
>eval "\$$1=\$2" while @ARGV && $ARGV[0]=~ /^(\w+)=(.*)/ && shift;
>
>and with similar functionality. I've decided I don't like
>getopt, because it seems to require me to write pages and pages
>of elif's as I add new arguments. It slows me down, whereas the
>perlism above liberates.
>
>My solution is a twenty-line python chunk equivalent to the perl one-liner.
>(Twenty lines because, to process a (name, value) pair, I have to find the
>current type of the variable "name" before setting "name" to righttype("value").
>
>I'm happy with this 20-line chunk and wish to re-use it in many python programs.
></motivation>
>
><question>
> What is the pythonic way to embed a 20-line chunk of code into a function?
>I'd love to define these 20 lines as a module, and reuse the module over and over.
>but this chunk of code needs to have access to
>the local variables of main, whatever they are called.
>
> In tcl, IIRC, the command "upvar" allows one function to get access to its
>parent function's local variables.
>
> Is there a pythonic way to tell a function "you are allowed to see all your
>parent's variables?" Or, to tell a chunk of code, "you are just a chunk of
>code, not really a function"?
></question>
>
You can see them, but you can't rebind them without nasty hacks.
I would suggest just instantiating an object that initializes the way
you want to contain the values you pre-specify, and optionally get
overridden by command line info as you specify. E.g., a quick hack (not
tested beyond what you see ;-)
----< clvalues.py >-----------------------------------------------------
class CLValues(dict):
"""
A dict whose initialization values are overridden by
-name value pairs in the overrides list, by default taken from
command line args sys.argv[1:], but a list may be passed.
Existing values get overridden by cmd line values converted
to the same type. New values are assumed str type. Existing
values may be specified non-overridable by prefixing an underscore,
which is removed after cmd line args have been processed.
Since keys are valid names, access is also provided via attribute syntax.
"""
def __init__(self, overrides=None, *args, **kw):
dict.__init__(self, *args, **kw)
if overrides is None: overrides = __import__('sys').argv[1:]
while overrides:
name = overrides.pop(0)
if not name.startswith('-') or not name[1:]:
raise ValueError, "Names must be non-null and prefixed with '-', unlike %r" % name
name = name[1:]
if '_'+name in self or name.startswith('_') and name in self:
raise ValueError, "%r may not be overridden" % name
if not overrides: raise ValueError, 'No value following %r'% '-'+name
value = overrides.pop(0)
self[name] = type(self.get(name, ''))(value) # default str type if not pre-existing
for k,v in self.items():
if k.startswith('_'): # make plain names for non-overridables
self[k[1:]] = v
del self[k]
def __getattr__(self, name): return self[name] # provide key access as attributes
def test():
clv = CLValues(
decode=0,
verbose=0,
bits=7,
N = 10000,
file="blah",
_securityLevel = 3)
for name, value in clv.items():
print '%15s: %r' %(name, value)
print 'N accessed as clv.N => %r' % clv.N
if __name__ == '__main__':
test()
------------------------------------------------------------------------
Running it to run the test:
[ 9:54] C:\pywk\ut>py24 clvalues.py -bits 8 -file other\path\and\file
decode: 0
securityLevel: 3
verbose: 0
file: 'other\\path\\and\\file'
bits: 8
N: 10000
N accessed as clv.N => 10000
[ 9:54] C:\pywk\ut>py24 clvalues.py -securityLevel 0
Traceback (most recent call last):
File "clvalues.py", line 44, in ?
test()
File "clvalues.py", line 38, in test
_securityLevel = 3)
File "clvalues.py", line 21, in __init__
raise ValueError, "%r may not be overridden" % name
ValueError: 'securityLevel' may not be overridden
Quoting command line arg to make a single arg with embedded spaces:
[ 9:54] C:\pywk\ut>py24 clvalues.py -added "should be string"
decode: 0
securityLevel: 3
added: 'should be string'
verbose: 0
file: 'blah'
bits: 7
N: 10000
N accessed as clv.N => 10000
>Thanks very much
>
De nada.
>David
>
>PS -- example below illustrates the chunk of code, in case anyone is interested.
>
<snip code, from which I tried to translate the functionality>
Usage in a program would go something like
from clvalues import CLValues
clv = CLValues(
# ... like test above
)
# ...
# use values spelled clv.name or clv['name'] or clv.get('name') etc
#
Regards,
Bengt Richter
More information about the Python-list
mailing list