views:

76

answers:

3

In PHP one can create a reference variable, so that two named variables can look at the same value:

$a = 1;
$b =& $a;
echo $a; // 1
echo $b; // 1
$b = 2;
echo $a; // 2

I'm looking to achieve something similar in Python. Specifically, I want to create a reference to an object's property, eg:

class Foo(object):
  @property
  def bar(self): return some_calculated_value

foo_instance = Foo()
ref = foo_instance.bar 
# so that 'ref' is referencing the bar property on foo, calculated when used.

Is this possible?

+3  A: 

There is some more magic that can be done in Python (not that I would recommend it and it will require digging on your part ;-), but using a closure may be sufficient for your needs:

get_x = lambda: foo_instance.bar
get_x() # yahoo!

Edit, for those wanting "update support", it's all about the closures:

def wrap_prop (obj, pname):
  def _access(*v):
    if not len(v):
      return getattr(obj, pname)
    else
      setattr(obj, pname, v[0])
  return _access

class z (object):
  pass

access = wrap_prop(z(), "bar")
access(20)
access() # yahoo! \o/

Without stepping outside the bounds of normally (for me :-) accepted Python, this could also be written to return an object with forwarding/proxy property, imagine:

access = wrap_prop(z(), "bar")
access.val = 20
access.val # yahoo \o/

Some interesting links:

pst
But it's not settable.
KennyTM
@KennyTM: neither is the property given in digitala's example.
JAB
@JAB: Did OP said his Python example is correct? I believe what OP wants is to reproduce [the PHP example](http://www.ideone.com/VdfrW) with $a becoming a property, not necessarily read-only.
KennyTM
+1  A: 

No, what you want is not possible. All names in Python are references, but they're always references to objects, not references to variables. You can't have a local name that, when "used", re-evaluates what it was that created it.

What you can have is an object that acts as a proxy, delegating most operations on it to operations on whatever it is referencing internally. However, this isn't always transparent, and there are some operations you can't proxy. It's also frequently inconvenient to have the thing you are proxying to change during an operation. All in all, it's usually better to not try this.

Instead, in your particular case, you would keep around foo_instance instead of ref, and just use foo_instance.bar whenever you wanted to "use" the ref reference. For more complicated situations, or for more abstraction, you could have a separate type with a property that did just what you wanted, or a function (usually a closure) that knew what to get and where.

Thomas Wouters
+1  A: 

As others have pointed out, in order to do this, you'll need to keep a reference to the parent object around. Without questioning your reasons for wanting to do this, here's a possible solution:

class PropertyRef:
    def __init__(self, obj, prop_name):
        klass = obj.__class__
        prop = getattr(klass, prop_name)
        if not hasattr(prop, 'fget'):
            raise TypeError('%s is not a property of %r' % (prop_name, klass))
        self.get = lambda: prop.fget(obj)
        if getattr(prop, 'fset'):
            self.set = lambda value: prop.fset(obj, value))

class Foo(object):
    @property
    def bar(self):
        return some_calculated_value

>>> foo_instance = Foo()
>>> ref = PropertyRef(foo_instance, 'bar')
>>> ref.get()  # Returns some_calculated_value
>>> ref.set(some_other_value)
>>> ref.get()  # Returns some_other_value

BTW, in the example you gave, the property is read-only (doesn't have a setter), so you wouldn't be able to set it anyway.

If this feels like an unnecessary amount of code, it probably is -- I'm almost certain you can find a better solution to your use case, whatever it is.

elo80ka