2010-07-21 28 views
5

Trong PHP người ta có thể tạo ra một biến tham chiếu, do đó hai biến được đặt tên có thể nhìn vào giá trị như nhau:Tạo một tham chiếu đến một biến (tương tự như "= &" của PHP)?

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

tôi đang tìm cách để đạt được một cái gì đó tương tự bằng Python. Cụ thể, tôi muốn tạo tham chiếu đến thuộc tính của đối tượng, ví dụ:

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. 

Điều này có thể không?

+3

Nếu bạn không sử dụng các thuộc tính, nhưng sử dụng các hàm phương thức, điều này là tầm thường. Nếu không, điều này có lẽ chỉ đơn giản là một lỗi đang chờ xảy ra. Tạo bí danh * tạo ra sự mơ hồ khó hiểu, khó hiểu và khó gỡ lỗi. Tại sao làm điều đó cho chính bạn hoặc những người sẽ cố gắng duy trì điều này? Trường hợp sử dụng cho sự mơ hồ như thế này là gì? –

+0

Tại sao bạn muốn làm điều đó? – NullUserException

+0

Đơn giản hóa: bí danh 'someproxyobject.aholdingvariableto.anothersubobject.property' thành' foo'. –

Trả lời

5

Có một số kỳ diệu hơn có thể được thực hiện bằng Python (không phải là tôi muốn giới thiệu nó và nó sẽ yêu cầu đào từ phía bạn ;-), nhưng sử dụng một kết thúc có thể là đủ cho nhu cầu của bạn:

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

chỉnh sửa, cho những người muốn "hỗ trợ cập nhật", đó là tất cả về việc đóng cửa:

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/ 

Nếu không bước ra ngoài giới hạn của thường (đối với tôi :-) chấp nhận Python, điều này cũng có thể được viết để trả lại một đối tượng với thuộc tính chuyển tiếp/proxy, hãy tưởng tượng:

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

Một số liên kết thú vị:

+0

Nhưng không thể cài đặt được. – kennytm

+0

@KennyTM: không phải là thuộc tính được đưa ra trong ví dụ của digitala. – JAB

+0

@JAB: OP có nói ví dụ Python của anh ấy là chính xác không? Tôi tin rằng những gì OP muốn là tái sản xuất [ví dụ PHP] (http://www.ideone.com/VdfrW) với $ a trở thành một tài sản, không nhất thiết phải chỉ đọc. – kennytm

1

Không, những gì bạn muốn là không thể. Tất cả các tên trong Python là tham chiếu, nhưng chúng luôn tham chiếu đến đối tượng, không tham chiếu đến biến số. Bạn không thể có một tên địa phương, khi "được sử dụng", hãy đánh giá lại những gì nó đã tạo ra nó.

Những gì bạn có thể là một đối tượng hoạt động như một proxy, ủy thác hầu hết các hoạt động trên proxy để hoạt động trên bất kỳ nội dung nào đang tham chiếu nội bộ. Tuy nhiên, điều này không phải lúc nào cũng trong suốt và có một số thao tác bạn không thể ủy quyền. Nó cũng thường xuyên bất tiện khi có điều bạn đang ủy quyền thay đổi trong thời gian một hoạt động. Tất cả trong tất cả, nó thường là tốt hơn để không thử này. Thay vào đó, trong trường hợp cụ thể của bạn, bạn sẽ giữ khoảng foo_instance thay vì ref và chỉ sử dụng foo_instance.bar bất cứ khi nào bạn muốn "sử dụng" tham chiếu ref. Đối với các tình huống phức tạp hơn, hoặc để trừu tượng hơn, bạn có thể có một kiểu riêng biệt với một thuộc tính mà chỉ làm những gì bạn muốn, hoặc một hàm (thường là một đóng) biết những gì cần nhận và ở đâu.

1

Như những người khác đã chỉ ra, để thực hiện việc này, bạn sẽ cần giữ một tham chiếu đến đối tượng cha mẹ xung quanh. Nếu không đặt câu hỏi lý do của bạn để muốn làm điều này, đây là một giải pháp có thể có:

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, trong ví dụ bạn đã cung cấp, thuộc tính là chỉ đọc (không có setter), vì vậy bạn sẽ không có thể thiết lập nó.

Nếu điều này giống như số lượng mã không cần thiết, có thể là - Tôi gần như chắc chắn bạn có thể tìm ra giải pháp tốt hơn cho trường hợp sử dụng của bạn, bất kể nó là gì.

Các vấn đề liên quan