创建对变量的引用(类似于PHP的“=&”)?

时间:2010-07-21 16:56:45

标签: python reference

在PHP中,可以创建一个引用变量,这样两个命名变量就可以看到相同的值:

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

我希望在Python中实现类似的功能。具体来说,我想创建一个对象属性的引用,例如:

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.

这可能吗?

3 个答案:

答案 0 :(得分:5)

可以在Python中完成更多魔术(不是我会推荐它,而是需要挖掘你的部分;-),但使用闭包可能足以满足您的需求:

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

编辑,对于那些想要“更新支持”的人来说,关键是闭包:

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/

如果没有超出正常范围(对我来说:-)接受Python,也可以编写这个以返回带有转发/代理属性的对象,想象一下:

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

一些有趣的链接:

答案 1 :(得分:1)

不,你想要的是不可能的。 Python中的所有名称都是引用,但它们始终引用对象,而不是对变量的引用。您不能拥有一个本地名称,当“使用”时,重新评估创建它的内容。

可以拥有的是一个充当代理的对象,将其上的大多数操作委托给内部引用的任何操作。但是,这并不总是透明的,并且有些操作无法代理。在操作期间,让您代理更改的事情通常也很不方便。总而言之,通常最好不要尝试这一点。

相反,在您的特定情况下,您将保留foo_instance而不是ref,并且只要您想“使用”foo_instance.bar引用,就可以使用ref。对于更复杂的情况,或者更多的抽象,你可以有一个单独的类型,其属性可以完成你想要的,或者是一个函数(通常是一个闭包),它知道要获取什么以及在哪里。

答案 2 :(得分:1)

正如其他人所指出的那样,为了做到这一点,你需要保持对父对象的引用。在不质疑您想要这样做的原因的情况下,这是一个可能的解决方案:

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,在您给出的示例中,该属性是只读的(没有setter),因此无论如何都无法设置它。

如果这感觉像一个不必要的代码量,它可能是 - 我几乎可以肯定你可以为你的用例找到更好的解决方案,无论它是什么。