代码之家  ›  专栏  ›  技术社区  ›  Phillip B Oldham

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

  •  5
  • Phillip B Oldham  · 技术社区  · 14 年前

    在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 回复  |  直到 14 年前
        1
  •  5
  •   user166390    14 年前

    在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的界限,也可以编写此命令来返回具有forwarding/proxy属性的对象,想象一下:

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

    一些有趣的链接:

        2
  •  1
  •   Thomas Wouters    14 年前

    不,你想要的是不可能的。python中的所有名称都是引用,但它们总是引用 物体 ,不是引用 变量 . 当“使用”时,不能有本地名称重新评估创建它的对象。

    你什么 可以 have是一个充当代理的对象,它将对其执行的大多数操作委托给对其内部引用的任何操作。但是,这并不总是透明的,而且有些操作您不能代理。你要改变的东西常常也不方便 在期间 手术。总之,最好不要尝试这个。

    相反,在你的特殊情况下,你会保持 foo_instance 而不是 ref 并且只是使用 foo_instance.bar 每当你想“使用”的时候 裁判 参考文献。对于更复杂的情况,或者对于更抽象的情况,您可以有一个单独的类型,该类型具有一个满足您需要的属性,或者一个函数(通常是一个闭包),该函数知道要得到什么和在哪里得到什么。

        3
  •  1
  •   elo80ka    14 年前

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

    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
    

    顺便说一句,在您给出的示例中,该属性是只读的(没有setter),因此您无论如何都无法设置它。

    如果这感觉像是一个不必要的代码量,那么它可能是——我几乎可以肯定您可以找到一个更好的解决方案来解决您的用例,不管它是什么。