在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.
这可能吗?
答案 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),因此无论如何都无法设置它。
如果这感觉像一个不必要的代码量,它可能是 - 我几乎可以肯定你可以为你的用例找到更好的解决方案,无论它是什么。