[Python-3000] in-out parameters

Nick Coghlan ncoghlan at gmail.com
Sun Apr 30 05:04:14 CEST 2006


Rudy Rudolph wrote:
> I don't much care about the syntax. The proposed "inout" reserved word could
> be "ref" or "&" or "in out". We could even do "param : inout [type]". Whatever.

A more flexible approach would be to look at weakref.proxy and develop a 
version that takes a strong reference to the object it contains instead of a 
weak reference. This approach means the same mechanism will work for closures 
as well as for parameter passing.

Then the usage looks like:

 >>> def f(param):
...     param += 5
...     print "Parameter modified:", param
...
 >>> x = 2
 >>> f(x)
Parameter modified: 7
 >>> print x
2
 >>> x = ref(2)
 >>> f(x)
Parameter modified: 7
 >>> print x
7

So it is up to the caller to decide whether they want to allow the function to 
modify their local namespace.

Closures can also selectively enable rebinding in a slightly more intuitive 
fashion than with boxing into a list. To use the infamous accumulator example:

 >>> def accum(n):
...     n = ref(n)
...     def increment(i):
...         n += i
...         return n.__value__
...     return increment
...     # Use 'return lambda i: n.__iadd__(i).__value__' instead of the last
...     # 4 lines if you prefer brevity to readability. Or you can go even
...     # further and use 'return lambda i, n=ref(n): n.__iadd__(i).__value__'
...     # as the sole line in the body of the function, although doing so
...     # slightly changes the signature of the returned function
...
 >>> inc = accum(2)
 >>> inc(5)
7
 >>> inc(3)
10


The one trick with this is that simple assignment to a proxy reference won't 
work properly. Instead, you need to write something like:

 >>> def f(param):
...      param = ref.bind(param, 5)
...      print "Parameter replaced:", param
...
 >>> x = 2
 >>> f(x)
Parameter replaced: 5
 >>> print x
2
 >>> x = ref(2)
 >>> f(x)
Parameter replaced: 5
 >>> print x
5

Cheers,
Nick.

-------------------------------
# The following naive version of ref was used for the above examples
# A real proxy type would modify its class dynamically whenever
# __value__ was rebound to a different type of object so that it
# only provided the methods that the referent exposed.
class ref(object):
     def __init__(self, referent):
         self.__value__ = referent
     # Proxying string representation
     def __str__(self):
         return str(self.__value__)
     # Proxying addition
     def __add__(self, other):
         return self.__value__ + other
     __radd__ = __add__
     def __iadd__(self, other):
         self.__value__ += other
         return self
     # Proxying assignment
     @staticmethod
     def bind(proxy, other):
         # Static method so it works for non-ref objects
         try:
             proxy.__value__ = other
         except AttributeError:
             return other
         else:
             return proxy


-- 
Nick Coghlan   |   ncoghlan at gmail.com   |   Brisbane, Australia
---------------------------------------------------------------
             http://www.boredomandlaziness.org


More information about the Python-3000 mailing list