2010-12-29 56 views
7

Nói rằng tôi có hai danh sách:Python tài liệu tham khảo dữ liệu cơ bản, danh sách cùng tham khảo

>>> l1=[1,2,3,4] 
>>> l2=[11,12,13,14] 

tôi có thể đưa đến những danh sách trong một tuple, hoặc từ điển, và dường như họ là tất cả tài liệu tham khảo lại danh sách ban đầu :

>>> t=(l1,l2) 
>>> d={'l1':l1, 'l2':l2} 
>>> id(l1)==id(d['l1'])==id(t[0]) 
True 
>>> l1 is d['l1'] is t[0] 
True 

Vì họ là những tài liệu tham khảo, tôi có thể thay đổi l1 và các dữ liệu được gọi trong tuple và thay đổi từ điển phù hợp:

>>> l1.append(5) 
>>> l1 
[1, 2, 3, 4, 5] 
>>> t 
([1, 2, 3, 4, 5], [11, 12, 13, 14]) 
>>> d 
{'l2': [11, 12, 13, 14], 'l1': [1, 2, 3, 4, 5]} 

Bao gồm nếu tôi thêm tài liệu tham khảo trong từ điển d hoặc tài liệu tham khảo có thể thay đổi trong các tuple t:

>>> d['l1'].append(6) 
>>> t[0].append(7) 
>>> d 
{'l2': [11, 12, 13, 14], 'l1': [1, 2, 3, 4, 5, 6, 7]} 
>>> l1 
[1, 2, 3, 4, 5, 6, 7] 

Nếu bây giờ tôi đặt l1 vào một danh sách mới, số lượng tài liệu tham khảo cho các danh sách ban đầu giảm:

>>> sys.getrefcount(l1) 
4 
>>> sys.getrefcount(t[0]) 
4 
>>> l1=['new','list'] 
>>> l1 is d['l1'] is t[0] 
False 
>>> sys.getrefcount(l1) 
2 
>>> sys.getrefcount(t[0]) 
3 

Và thêm hoặc thay đổi l1 không thay đổi d['l1'] hoặc t[0] vì giờ đây là tham chiếu mới. Khái niệm tham chiếu gián tiếp là covered fairly well trong tài liệu Python nhưng không hoàn toàn.

Câu hỏi của tôi:

  1. Là một đối tượng có thể thay đổi luôn một tài liệu tham khảo? Bạn có thể luôn luôn giả định rằng sửa đổi nó sửa đổi bản gốc (Trừ khi bạn đặc biệt tạo một bản sao với l2=l1[:] loại thành ngữ)?

  2. Tôi có thể tập hợp danh sách tất cả các tham chiếu tương tự bằng Python không? tức là, một số chức năng f(l1) trả về ['l1', 'd', 't'] nếu tất cả những người đó đang đề cập đến cùng một danh sách?

  3. Giả định của tôi là không có vấn đề gì, dữ liệu sẽ vẫn hợp lệ miễn là có một số tham chiếu đến nó.

ví dụ:

l=[1,2,3]   # create an object of three integers and create a ref to it 
l2=l    # create a reference to the same object 
l=[4,5,6]   # create a new object of 3 ints; the original now referenced 
        # by l2 is unchanged and unmoved 
+0

Có liên quan cho 3: http://docs.python.org/library/weakref.html –

Trả lời

6

1) Sửa đổi một đối tượng có thể thay đổi thông qua một tài liệu tham khảo sẽ luôn sửa đổi "bản gốc". Thành thật mà nói, điều này phản bội một sự hiểu lầm về tài liệu tham khảo. Tham chiếu mới hơn cũng giống như tham chiếu "gốc" như bất kỳ tham chiếu nào khác. Vì vậy, miễn là cả hai tên trỏ đến cùng một đối tượng, việc sửa đổi đối tượng thông qua một trong hai tên sẽ được phản ánh khi được truy cập thông qua tên khác.

2) Không chính xác như những gì bạn muốn. gc.get_referrers trả về tất cả các tham chiếu cho đối tượng.

>>> l = [1, 2] 
>>> d = {0: l} 
>>> t = (l,) 
>>> import gc 
>>> import pprint 
>>> pprint.pprint(gc.get_referrers(l)) 
[{'__builtins__': <module '__builtin__' (built-in)>, 
    '__doc__': None, 
    '__name__': '__main__', 
    '__package__': None, 
    'd': {0: [1, 2]}, 
    'gc': <module 'gc' (built-in)>, 
    'l': [1, 2], 
    'pprint': <module 'pprint' from '/usr/lib/python2.6/pprint.pyc'>, 
    't': ([1, 2],)}, # This is globals() 

{0: [1, 2]}, # This is d 
([1, 2],)] # this is t 

Lưu ý rằng đối tượng thực sự được tham chiếu bởi l không được bao gồm trong danh sách được trả về vì nó không chứa tham chiếu đến chính nó. globals() được trả về vì không chứa tham chiếu đến danh sách gốc.

3) Nếu hợp lệ, ý của bạn là "sẽ không bị thu gom rác" thì điều này đúng là chặn một lỗi không chắc chắn. Nó sẽ là một nhà sưu tập rác rất tiếc, đã "đánh cắp" dữ liệu của bạn.

0

1- Đối tượng có thể thay đổi luôn là tham chiếu ? Bạn có thể luôn luôn giả định rằng sửa đổi nó sửa đổi gốc (Trừ khi bạn đặc biệt tạo một bản sao với l2 = l1 [:] loại thành ngữ)?

Có. Trên thực tế các đối tượng không thể thay đổi luôn là tham chiếu. Bạn không thể thay đổi chúng để cảm nhận điều này.

2 - Tôi có thể tập hợp danh sách tất cả các tài liệu tham khảo tương tự bằng Python không? tức là, một số hàm f (l1) trả về ['l1', 'd', 't'] nếu tất cả những thứ đó là đề cập đến cùng một danh sách?

Điều đó thật kỳ lạ nhưng có thể thực hiện được.

Bạn có thể so sánh các đối tượng cho "mẫu" với toán tử is. Giống như trong l1 is t[0]

Và bạn có thể nhận được tất cả gọi đến đối tượng với chức năng gc.get_referrers trong module thu gom rác (gc) - Bạn có thể kiểm tra những dẫn đến nhiều chỉ o đối tượng của bạn với các nhà điều hành is. Vì vậy, có, nó có thể được thực hiện. Tôi không nghĩ đó là một ý hay. Đó là nhiều khả năng is điều hành phục vụ một cách để bạn có thể làm những gì bạn cần một mình

3- Đó là giả định của tôi rằng không có vấn đề gì , dữ liệu sẽ vẫn có hiệu lực nên miễn là có một số tài liệu tham khảo cho nó.

Có.

0

Đối tượng có thể thay đổi luôn là tham chiếu không? Bạn có thể luôn luôn giả định rằng sửa đổi nó sửa đổi bản gốc (Trừ khi bạn đặc biệt tạo một bản sao với l2 = l1 [:] loại thành ngữ)?

Python có ngữ nghĩa tham khảo: biến không cửa hàng giá trị như trong C++, nhưng thay vào đó nhãn họ. Khái niệm "bản gốc" là thiếu sót: nếu hai biến có cùng giá trị, nó hoàn toàn không liên quan đến cái nào "đến trước". Nó không quan trọng nếu đối tượng là có thể thay đổi hay không (ngoại trừ các đối tượng bất biến sẽ không làm cho nó dễ dàng như vậy để nói những gì đang xảy ra đằng sau hậu trường). Để tạo bản sao theo cách tổng quát hơn, hãy thử mô-đun copy.

Tôi có thể tập hợp danh sách tất cả các tham chiếu tương tự bằng Python không? tức là, một số hàm f (l1) trả về ['l1', 'd', 't'] nếu tất cả những hàm này đều tham chiếu đến cùng một danh sách?

Không dễ dàng. Tham khảo câu trả lời của aaronasterling để biết chi tiết.Bạn cũng có thể thử một cái gì đó như k for k, v in locals().items() if v is the_object, nhưng bạn cũng sẽ phải tìm kiếm globals(), bạn sẽ bỏ lỡ một số thứ và nó có thể gây ra một số loại vấn đề do đệ quy với tên 'k' và 'v' (tôi đã không thử nghiệm).

Giả định của tôi là không có vấn đề gì, dữ liệu sẽ vẫn hợp lệ miễn là có một số tham chiếu đến nó.

Tuyệt đối.

0
  1. "... đối tượng là tham chiếu ..." là vô nghĩa. Tham chiếu không phải là đối tượng. Biến, trường thành viên, vị trí trong danh sách và tập hợp, v.v. giữ tham chiếu và các tham chiếu này trỏ đến đối tượng. Có thể có bất kỳ số nào (trong một triển khai không refcouting, thậm chí không ai - tạm thời, tức là cho đến khi GC đá vào) tham chiếu đến một đối tượng. Tất cả những người có một tham chiếu đến một đối tượng có thể gọi nó là phương pháp, truy cập các thành viên của nó, vv - điều này là đúng cho tất cả các đối tượng. Tất nhiên chỉ có thể thay đổi các đối tượng có thể thay đổi theo cách này, vì vậy bạn thường không quan tâm đến những vật không thay đổi được.
  2. Có, như những người khác đã hiển thị. Nhưng điều này không cần thiết trừ khi bạn đang gỡ lỗi GC hoặc theo dõi xuống một rò rỉ bộ nhớ nghiêm trọng trong mã của bạn - tại sao bạn nghĩ rằng bạn cần điều này?
  3. Python có quản lý bộ nhớ tự động, vì vậy có. Miễn là có một tham chiếu đến một đối tượng, nó sẽ không bị xóa (tuy nhiên, nó có thể vẫn còn sống trong một thời gian sau khi nó trở thành không thể truy cập, do tham chiếu tuần hoàn và thực tế là GC chỉ chạy một lần trong một thời gian).
3

Mỗi biến số trong Python là tham chiếu.

Đối với danh sách, bạn đang tập trung vào kết quả của phương pháp append() và mất tầm nhìn lớn hơn về cấu trúc dữ liệu Python. Có các phương pháp khác trong danh sách, và có những ưu điểm và hậu quả đối với cách danh sách được xây dựng. Nó là hữu ích để suy nghĩ của danh sách như xem trên các đối tượng khác được đề cập trong danh sách. Chúng không "chứa" bất kỳ điều gì khác ngoài các quy tắc và cách truy cập dữ liệu được các đối tượng trong đó đề cập đến.

Các list.append(x)method specifically tương đương với l[len(l):]=[list]

Vì vậy:

>>> l1=range(3) 
>>> l2=range(20,23) 
>>> l3=range(30,33) 
>>> l1[len(l1):]=[l2] # equivalent to 'append' for subscriptable sequences 
>>> l1[len(l1):]=l3  # same as 'extend' 
>>> l1 
[0, 1, 2, [20, 21, 22], 30, 31, 32] 
>>> len(l1) 
7 
>>> l1.index(30) 
4 
>>> l1.index(20) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
ValueError: list.index(x): x not in list 
>>> 20 in l1 
False 
>>> 30 in l1 
True 

Bằng cách đặt các nhà xây dựng danh sách khoảng l2 trong l1[len(l1):]=[l2], hoặc gọi l.append(l2), bạn tạo một tài liệu tham khảo đó là ràng buộc để l2. Nếu bạn thay đổi l2, tham chiếu cũng sẽ hiển thị thay đổi. Độ dài của danh sách đó là một phần tử đơn lẻ - tham chiếu đến chuỗi được nối thêm.

Không có phím tắt của hàm tạo như trong l1[len(l1):]=l3, bạn sao chép từng phần tử của chuỗi.

Nếu bạn sử dụng các phương pháp danh sách phổ biến khác, chẳng hạn như l.index(something) hoặc in, bạn sẽ không tìm thấy các phần tử bên trong tham chiếu dữ liệu. l.sort() sẽ không sắp xếp đúng cách. Chúng hoạt động "nông" trên đối tượng và bằng cách sử dụng l1[len(l1):]=[l2], bạn hiện đang tạo cấu trúc dữ liệu đệ quy.

Nếu bạn sử dụng l1[len(l1):]=l3, bạn đang tạo bản sao đúng (nông) của các phần tử trong l3.

Đây là những thành ngữ Python khá cơ bản và phần lớn thời gian chúng làm điều đúng. ' Bạn có thể, tuy nhiên, có được kết quả đáng ngạc nhiên, chẳng hạn như:

>>> m=[[None]*2]*3 
>>> m 
[[None, None], [None, None], [None, None]] 
>>> m[0][1]=33 
>>> m 
[[None, 33], [None, 33], [None, 33]] # probably not what was intended... 
>>> m[0] is m[1] is m[2]    # same object, that's why they all changed 
True 

Một số người mới Python cố gắng tạo ra một không gian đa bằng cách làm một cái gì đó giống như m=[[None]*2]*3 Các sequence replication tác phẩm đầu tiên như mong đợi; nó tạo ra 2 bản sao của None. Đây là vấn đề thứ hai, nó tạo ra ba bản sao của tham chiếu đến danh sách đầu tiên. Vì vậy, hãy nhập m[0][1]=33 sửa đổi danh sách bên trong danh sách được gắn với m và sau đó tất cả các tham chiếu bị ràng buộc thay đổi để hiển thị thay đổi đó.

So sánh với:

>>> m=[[None]*2,[None]*2,[None]*2] 
>>> m 
[[None, None], [None, None], [None, None]] 
>>> m[0][1]=33 
>>> m 
[[None, 33], [None, None], [None, None]] 

Bạn cũng có thể sử dụng nested list comprehensions làm tương tự như vậy:

>>> m=[[ None for i in range(2)] for j in range(3)] 
>>> m 
[[None, None], [None, None], [None, None]] 
>>> m[0][1]=44 
>>> m 
[[None, 44], [None, None], [None, None]] 
>>> m[0] is m[1] is m[2]      # three different lists.... 
False 

Đối với danh sách và tài liệu tham khảo, Fredrik Lundh có this text cho một giới thiệu tốt.

Đối với câu hỏi cụ thể của bạn:

1) Trong Python, Tất cả mọi thứ là một nhãn hoặc một tham chiếu đến một đối tượng. Không có 'bản gốc' (khái niệm C++) và không có sự phân biệt giữa 'tham chiếu', con trỏ hoặc dữ liệu thực tế (khái niệm C/Perl)

2) Fredrik Lundh có sự tương tự tuyệt vời về tham chiếu to a question similar to this:

cách giống như bạn lấy tên của rằng mèo bạn tìm thấy trên hiên nhà của bạn: mèo (object) tự nó không thể cho bạn biết tên của nó, và nó không thực sự quan tâm - vì vậy các cách duy nhất để tìm hiểu những gì nó được gọi là yêu cầu tất cả các hàng xóm của bạn (không gian tên) nếu đó là mèo (đối tượng) của họ ...

.... và đừng ngạc nhiên nếu bạn thấy rằng nó được nhiều tên gọi, hoặc không có tên nào cả!

Bạn có thể tìm thấy danh sách này với một số nỗ lực, nhưng tại sao? Chỉ cần gọi nó là những gì bạn sẽ gọi nó - giống như một con mèo tìm thấy.

3) True.

0
1a. Is a mutable object always a reference? 

Không có sự khác biệt giữa các đối tượng có thể thay đổi và không thể thay đổi. Thấy tên biến là tài liệu tham khảo là hữu ích cho những người có nền C (nhưng ngụ ý họ có thể bị bỏ qua, mà họ không thể).

1b. Can you always assume that modifying it modifies the original 

Xin vui lòng, nó không phải là "bản gốc". Đó là cùng một đối tượng. b = một phương tiện b và bây giờ là cùng một đối tượng.

1c. (Unless you specifically make a copy with l2=l1[:] kind of idiom)? 

Phải, bởi vì sau đó không còn là đối tượng nữa. (Mặc dù các mục n danh sách sẽ là các đối tượng tương tự như danh sách gốc).

2. Can I assemble a list of all the same references in Python? 

Có, có thể, nhưng bạn sẽ không bao giờ cần đến nó, vì vậy sẽ lãng phí năng lượng. :)

3. It is my assumption that no matter what, the data will remain valid so long as there is some reference to it. 

Có, đối tượng sẽ không được thu thập rác miễn là bạn có tham chiếu đến nó. (Sử dụng từ "hợp lệ" ở đây có vẻ không đúng, nhưng tôi cho rằng đây là ý của bạn).

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