2010-07-21 39 views
5

在PHP中可以創建一個參考變量,這樣兩個命名變量可以看看相同的值:創建一個對變量的引用(類似於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

如果您不使用屬性,但使用方法函數,這是微不足道的。否則,這可能只是一個等待發生的錯誤。創建一個*別名會創建故意,難以理解和難以調試的模糊性。爲什麼要對你自己或那些試圖維持這一點的人進行呢?這種歧義的用例是什麼? – 2010-07-21 16:59:35

+0

你爲什麼要這麼做? – NullUserException 2010-07-21 18:37:08

+0

簡化:將'someproxyobject.aholdingvariableto.anothersubobject.property'別名到'foo'。 – 2010-07-22 07:05:01

回答

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/ 

一些相關鏈接:

+0

但它不可設置。 – kennytm 2010-07-21 17:16:57

+0

@KennyTM:既不是digitala示例中給出的屬性。 – JAB 2010-07-21 17:48:15

+0

@JAB:OP說他的Python例子是正確的嗎?我相信OP希望重現[PHP示例](http://www.ideone.com/VdfrW),其中$ a成爲一個屬性,不一定是隻讀的。 – kennytm 2010-07-21 18:02:49

1

不,你想要什麼是不可能的。 Python中的所有名稱都是引用,但它們總是引用對象,而不是引用變量。你不能有一個本地名稱,當「使用」時,重新評估它創建它的是什麼。

什麼你可以有就是充當代理,委託它的大多數操作上不管它是內部引用操作的對象。但是,這並不總是透明的,並且有一些操作無法代理。在操作期間,將代理的內容更改爲通常也很不方便。總而言之,不要嘗試這種做法通常會更好。

相反,你的具體情況,你會保持周圍foo_instance而不是ref,並只使用foo_instance.bar只要你想「用」 ref參考。對於更復雜的情況,或者更抽象的情況,你可以擁有一個單獨的類型,其屬性可以做你想要的,或者是一個函數(通常是閉包),它知道要得到什麼以及在哪裏。

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 

順便說一句,在你給的例子,該屬性是隻讀的(沒有一個二傳手),這樣你就不會無論如何都可以設置它。如果這感覺像是不必要的代碼量,它可能是 - 我幾乎可以肯定你可以找到更好的解決方案,無論它是什麼。

相關問題