Welcome, guest | Sign In | My Account | Store | Cart

This is a container class, suitable for use to answer the question "How do I pass a reference to a variable to a function", abusing some of the methods to get a syntax that's easier to use than more conventional containers.

Python, 23 lines
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class Ref(object):
    _unbound = object()
    def __new__(cls, value = _unbound):
        """We're an object, but need to ignore the optional argument."""

        return object.__new__(cls)

    def __init__(self, value = _unbound):
        """Bind the  optional value, if provided."""
        if value is not self._unbound:
            self._value = value

    def __pos__(self):
        """Return value, if bound."""
        try:
            return self._value
        except AttributeError:
            raise NameError, "%s object does not have a value stored." % \
                  self.__class__.__name__

    def __iadd__(self, value):
        self._value = value
        return self

A common question on comp.lang.python is "How do I pass a reference to a variable to change it in a function." This usually comes from people used to other languages, where that's the solution of choice for returning multiple values. The better solution for this in Python is to return a tuple and assign the new value to the variable. However, answers involving using a container class for the variable always surface, with the usual objection that the syntax for them is ugly.

The Ref class is designed to be a simple container class with a cleaner syntax than other alternatives. It abuses the ability to have operators invoke methods to use the monadic plus and add-assign operator to retrieve and set the values in the container. I.e.:

a = Ref(20) print +a # Prints 20 b = a b += 23 print +a # Prints 23 a += "Testing" print +b # Prints 23

2 comments

Josiah Carlson 18 years, 5 months ago  # | flag

The problem with your solution is that you must wrap all of the underlying methods to be effective. I personally prefer the standard answer of "use a list."

ref = [obj]
Mike Meyer (author) 18 years, 4 months ago  # | flag

No other wrappers needed. I clearly didn't provide sufficient examples. You use a Ref object just like you'd use a list, except the syntax for setting/reading a value looks more like an extended lambda-calculus Cell than a list. Where you'd write arg[0] in a method if you passed a list, you'd write +arg to get the value, and arg[0] = value becomes arg += value.

To write the classic "inc" function, you'd write:

def inc(x):
  x += +x
Created by Mike Meyer on Tue, 15 Nov 2005 (PSF)
Python recipes (4591)
Mike Meyer's recipes (1)

Required Modules

  • (none specified)

Other Information and Tasks