binding a reference to a variable

Bengt Richter bokr at oz.net
Tue Apr 9 20:07:38 EDT 2002


On Tue, 9 Apr 2002 19:23:18 GMT, Andrew Koenig <ark at research.att.com> wrote:

>I would like to be able to write an expression that yields an
>object that I can subsequently use to rebind a name that I mention
>only in that expression.  How do I do it?
>
>My motivation is to be able to write something that is analogous
>to call-by-reference in C++.
>
>This question, as phrased, is probably a little hard to understand;
>here are some examples that might help.
>
>Here's a function definition:
>
>        def f(v):
>                global x
>                x = v
>
>Now, f is an object that I can use to rebind the name x.  For
>example, if I execute f(42), that sets x to 42.
>
>However, this example doesn't do what I want because the
>``expression'' in this example would have to be f, not the definition
>of f (which isn't an expression).  The name x is not mentioned
>anywhere in the expression.  Therefore, each time I want to affect a
>different variable this way, I have to define a new function.
>
>What I would really like is to be able to define a function called,
>say, `set' such that set(x, 42) has the same effect as `x = 42'.
>
>I can't use a lambda expression, because they're not allowed to
>contain assignments.
>
>So far, the closest I've been able to come is this:
>
>        def set(var, val):
>                var[:] = [val]
>                
>It requires that the variable in question be primed by giving it
>a list as its value, and detects failure to do so:
>
>        set(x, 42)              # error -- x is not a list
>        x = []
>        set(x, 42)              # x is now [42]
>
>Is it possible to do better (i.e., to solve this problem more succinctly)?
>
You've probably thought of this (using a class instance instead of []),
but maybe commenting on it will help us see where you're going:

 >>> class Ref:
 ...     def __init__(self, thing): self.thing = thing
 ...     def __call__(self, *newthing):
 ...         if newthing: self.thing = newthing[0]
 ...         return self.thing
 ...     def __repr__(self): return repr(self.thing)
 ...     __str__ = __repr__
 ...
 >>> x = Ref(42)
 >>> x
 42
 >>> x, x(23), x
 (23, 23, 23)

(Function eval got priority, unlike order in print args):

 >>> print x, x(42), x
 23 42 42
 >>> def foo(y):
 ...     y('set by foo')
 ...     return 'returned by foo'
 ...
 >>> x
 42
 >>> foo(x)
 'returned by foo'
 >>> x
 'set by foo'
 >>> x(100)
 100
 >>> x()+5
 105
 >>> x
 100
 >>> x+5
 Traceback (most recent call last):
   File "<stdin>", line 1, in ?
 TypeError: unsupported operand types for +: 'instance' and 'int'

I.e,. it's the str/repr methods of the Ref instance x that are showing the
printed results, not a automatic retrieval of the thing values followed by
str conversion, so you have to write x() to get at the actual value or
x(newvalue) to set and also get it.

Of course you can also write methods for x to participate in various operator
expressions besides being called with ().

Regards,
Bengt Richter



More information about the Python-list mailing list