2013-02-21 17 views
12

Bạn có thể coi trọng một id biến được truy xuất từ ​​hàm id bằng Python không? Ví dụ:Có thể dereference variable id's?

dereference(id(a)) == a 

Tôi muốn biết từ quan điểm học tập; Tôi hiểu rằng có nhiều phương pháp thực tế hơn.

+1

FWIW, IMHO đánh dấu đây là như một bản sao của một câu hỏi mà chấp nhận câu trả lời về cơ bản là "có thể bạn không muốn làm điều đó" không phải là hữu ích. – martineau

+0

@martineau: cũng có những câu trả lời khác nữa :) –

Trả lời

21

Dưới đây là một chức năng hữu ích dựa trên một comment do "Tiran" trong các cuộc thảo luận Hophat Abc referenced mà sẽ làm việc trong cả hai Python 2 và 3:

import _ctypes 

def di(obj_id): 
    """ Inverse of id() function. """ 
    return _ctypes.PyObj_FromPtr(obj_id) 

if __name__ == '__main__': 
    a = 42 
    b = 'answer' 
    print(di(id(a))) # -> 42 
    print(di(id(b))) # -> answer 
+2

Mã vui nhộn, nguy hiểm nhất mà tôi từng thấy trong một thời gian. –

+2

@NickT: YOLO ;-) – martineau

+0

Nhưng hãy cảnh báo rằng điều này sẽ làm gián đoạn thông dịch viên nếu bạn chuyển cho nó một địa chỉ không hợp lệ (vì đó là do rác được thu thập). – asmeurer

3

Không dễ dàng.

Bạn có thể kiểm tra lại danh sách gc.get_objects(), kiểm tra từng đối tượng nếu nó có cùng số id() nhưng điều đó không thực tế lắm.

Chức năng id()không được dự định sẽ không thể chấp nhận được; thực tế là nó được dựa trên địa chỉ bộ nhớ là một chi tiết thực hiện CPython, rằng việc triển khai Python khác không tuân theo.

+0

Given: 'a = 1',' b = a', 'c = a' ... a, b, c tất cả đều có cùng một' id() '. –

+3

Chắc chắn, họ có cùng một id. Điều đó có liên quan gì với câu hỏi OP? –

+0

Chỉ cần lưu ý rằng tham chiếu của một biến là tất cả cùng một đối tượng. –

2

Có một số cách và nó không phải là khó khăn để làm:

Trong O (n)

In [1]: def deref(id_): 
    ....:  f = {id(x):x for x in gc.get_objects()} 
    ....:  return f[id_] 

In [2]: foo = [1,2,3] 

In [3]: bar = id(foo) 

In [4]: deref(bar) 
Out[4]: [1, 2, 3] 

Một cách nhanh hơn trên trung bình, từ các ý kiến ​​(nhờ @Martijn Pieters):

def deref_fast(id_): 
    return next(ob for ob in gc.get_objects() if id(ob) == id_) 

Giải pháp nhanh nhất là trong câu trả lời từ @martineau, nhưng không yêu cầu phơi bày nội bộ python. Các giải pháp trên sử dụng cấu trúc python chuẩn.

+2

Bây giờ bạn đã tạo một tham chiếu đến * mọi giá trị trong bộ nhớ * đảm bảo rằng chúng sẽ không bị thu gom rác. Bạn thực sự muốn sử dụng [module 'weakref'] (http://docs.python.org/2/library/weakref.html#weakref.WeakValueDictionary) để thay thế. –

+0

OP được hỏi từ quan điểm học tập, không phải là quan điểm thực tế. – munk

+0

Nhưng OP sẽ không phải là người duy nhất xem xét điều này; ý tưởng tạo ra một ánh xạ của id-to-object là tốt đẹp, nhưng nó có những hậu quả nhất định mà bạn cần phải biết. –

1

Dưới đây là thêm một câu trả lời được chuyển thể từ chưa comment khác, một trong những điều này bằng cách "Peter Fein", trong phần thảo luận Hophat Abc tham chiếu trong câu trả lời của riêng mình cho câu hỏi của chính mình .

Mặc dù không phải là câu trả lời chung nhưng có thể vẫn hữu ích trong trường hợp bạn biết điều gì đó về lớp của đối tượng có id bạn muốn tra cứu - trái ngược với id là mọi thứ. Ý tưởng cơ bản là tạo một lớp theo dõi các cá thể và các lớp con của chính nó. Tôi cảm thấy đây có thể là một kỹ thuật đáng giá ngay cả với giới hạn đó.

import weakref 

class InstanceTracker(object): 
    """ base class that tracks instances of its subclasses using weakreferences """ 
    class __metaclass__(type): 
     """ Metaclass for InstanceTracker """ 
     def __new__(cls, name, bases, dic): 
      cls = super(cls, cls).__new__(cls, name, bases, dic) 
      cls.__instances__ = weakref.WeakValueDictionary() 
      return cls 

    def __init__(self, *args, **kwargs): 
     self.__instances__[id(self)]=self 
     super(InstanceTracker, self).__init__(*args, **kwargs) 

    @classmethod 
    def find_instance(cls, obj_id): 
     return cls.__instances__.get(obj_id, None) 

if __name__ == '__main__': 
    class MyClass(InstanceTracker): 
     def __init__(self, name): 
      super(MyClass, self).__init__() 
      self.name = name 
     def __repr__(self): 
      return '{}({!r})'.format(self.__class__.__name__, self.name) 

    obj1 = MyClass('Bob') 
    obj2 = MyClass('Sue') 

    print MyClass.find_instance(id(obj1)) 
    print MyClass.find_instance(id(obj2)) 
    print MyClass.find_instance(42) 

Output:

MyClass('Bob') 
MyClass('Sue') 
None