Python - как проверить / открыть список ссылок?

1

Одним из наиболее запутанных аспектов в python является создание списка списков (при условии, что один не использует numpy) - например, если вы попытаетесь сделать это с помощью более простого умножения, вы получите ссылочные копии:

In [1]: a = [[0] * 4] * 4
In [2]: a
Out[2]: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

In [3]: a[0][1] = 1
In [4]: a
Out[4]: [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]]

Как упоминалось в различных других публикациях SO, таких как этот, правильный способ создания экземпляра без каких-либо ссылок будет следующим:

In [5]: b = [[0 for i in range(4)] for i in range(4)]
In [6]: b         
Out[6]: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

In [7]: b[0][1] = 1
In [8]: b                                           
Out[8]: [[0, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]

Вопрос заключается в следующем: предположим, что каждый определяет свой список как со списком a, есть ли способ проверить массив таким образом, чтобы он показал, что он использует ссылки? Простая печать массива не будет раскрывать ссылки.

  • 0
    Ссылки используются в обоих случаях. Для CPython есть sys.getrefcount() который может указывать, сколько ссылок указывают на объект
  • 0
    Все объекты в Python имеют адрес.
Теги:
arrays
list
reference

2 ответа

0

Сначала немного терминологии: вы говорите о списках (а не массивах), которые всегда хранят ссылки на свои элементы.

Быстрый способ проверить, все ли ссылки в списке относятся к разным объектам:

>>> l1 = [[0, 1], [0, 1]]
>>> l2 = [[0, 1]]*2
>>> 
>>> len(set(map(id, l1))) == len(l1) # no duplicates
True
>>> len(set(map(id, l2))) == len(l2) # duplicates
False

который просто проверяет, есть ли n уникальных идентификаторов для объектов в списке длины n.

Если в вашем списке очень большое количество элементов, было бы более эффективно сделать это лениво и вернуть False для первого дублированного идентификатора.

def all_unique(lst):
    seen = set()
    for x in lst:
        id_ = id(x)
        if id_ in seen:
            return False
        seen.add(id_)
    return True

... работает так:

>>> all_unique(l1)
True
>>> all_unique(l2)
False
0

Вы можете использовать функцию id:

>>> a = [[0] * 4] * 4
>>> a
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> [id(sublist) for sublist in a]
[1975671202696, 1975671202696, 1975671202696, 1975671202696]
>>> b = [[0 for i in range(4)] for i in range(4)]
>>> b
[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
>>> [id(sublist) for sublist in b]
[1975671204808, 1975671205128, 1975671205000, 1975671204872]

Как вы можете видеть, в a идентификаторы одинаковы, а в b они разные.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню