Что происходит, когда я назначаю список с собственными ссылками на копию списка с синтаксисом фрагмента `mylist [:] = [mylist, mylist, ...]`? - PullRequest
0 голосов
/ 28 ноября 2018

Я только что посмотрел на реализацию functools.lru_cache , когда наткнулся на этот фрагмент:

root = []  # root of the circular doubly linked list
root[:] = [root, root, None, None]  # initialize by pointing to self

Я знаком с круговыми и двусвязными списками.Я также знаю, что new_list = my_list[:] создает копию my_list.При поиске назначений срезов или других реализаций круговых двусвязных списков я не мог найти никакой дополнительной информации об этом конкретном синтаксисе.

Вопросы:

  1. Чтопроисходит в этой ситуации.
  2. Существует ли другой синтаксис для достижения того же результата?
  3. Есть ли другой общий вариант использования для some_list[:] = some_iterable (без ссылки на себя)?

Ответы [ 3 ]

0 голосов
/ 28 ноября 2018

Просто посмотрите на разобранный код:

In [1]: def initializer():
   ...:     root = []  # root of the circular doubly linked list
   ...:     root[:] = [root, root, None, None]
   ...:     

In [2]: 

In [2]: import dis

In [3]: dis.dis(initializer)
  2           0 BUILD_LIST               0
              2 STORE_FAST               0 (root)

  3           4 LOAD_FAST                0 (root)
              6 LOAD_FAST                0 (root)
              8 LOAD_CONST               0 (None)
             10 LOAD_CONST               0 (None)
             12 BUILD_LIST               4
             14 LOAD_FAST                0 (root)
             16 LOAD_CONST               0 (None)
             18 LOAD_CONST               0 (None)
             20 BUILD_SLICE              2
             22 STORE_SUBSCR
             24 LOAD_CONST               0 (None)
             26 RETURN_VALUE

Вам нужен STORE_SUBSCR код операции, который предназначен для реализации следующего:

mplements TOS1[TOS] = TOS2

Что связано сделать документацию на месте операций.И если вам интересно, что такое операции на месте, вот как это определяет документ:

Операции на месте похожи на двоичные операции, в которых они удаляют TOS и TOS1 и возвращают результат обратно.стек, но операция выполняется на месте, когда TOS1 поддерживает его, и результирующее TOS может быть (но не обязательно) оригинальным TOS1.

Это будет проверять, что встроенный документв исходном коде написано:

инициализировать, указав на себя.

По поводу других ваших вопросов:

Есть ли другой синтаксис длядостичь того же результата?

Да, вы можете, как уже упоминалось в другом ответе, очистить и установить элементы списка, используя атрибут list.extend.Или назначьте элементы один за другим, может быть, lol

Есть ли другой общий случай использования some_list [:] = some_iterable (без ссылки на себя)?

Этоочень расплывчатый вопрос, потому что это то, что есть.Присвоение предметов Инъективным образом, что может быть полезным при замене предметов без воссоздания ссылок и т. Д.

0 голосов
/ 28 ноября 2018
  1. Что происходит в этой ситуации?

Если в списке l, вызывается l[:] = items l.__setitem__(slice(None), items).Этот метод назначает соответствующие элементы из заданной итерации списку после его очистки.

Есть ли другой синтаксис для достижения того же результата?

Вы можете сделать

l.clear()
l.extend(items)
Существует ли другой типичный вариант использования для some_list[:] = some_iterable (without the self reference)?

Теоретически, вы можете поместить в список любую итерацию.

0 голосов
/ 28 ноября 2018

in

root[:] = [root, root, None, None]

левое назначение среза просто говорит, что ссылка root используется повторно для хранения содержимого правой части.

Таким образом, root ссылка никогда не меняетсяи да, в списке вы можете ссылаться на себя (но не пытайтесь рекурсивно сглаживать их :).В этом случае в представлении отображается «рекурсия по списку».

>>> root
[<Recursion on list with id=48987464>,
 <Recursion on list with id=48987464>,
 None,
 None]

, и при печати она показывает многоточие:

>>> print(root)
[[...], [...], None, None]

обратите внимание, что для этого вам не нужно присваивать срезы.Есть простые способы вызвать рекурсию:

>>> root = []
>>> root.append(root)
>>> root
[<Recursion on list with id=51459656>]
>>> 

с использованием append не меняет ссылку, как мы все знаем, она просто мутирует список, добавляя ссылку на себя.Может быть, легче понять.

...