При использовании del с нарезкой сначала создается новый объект, а затем удаляется? Будет ли он на месте?

Я хочу знать, создает ли нарезка копию списка и используем ли мы del над срезом. Тогда не создаст ли он копию, т.е. сначала новый объект из списка для данного слайса, а потом удалит его?

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

# suppose if I use something like this:
a = [1,2,3,4,5,6,7,8,9,0]
del a[5:]

Итак, не создаст ли этот del [a:] копию a в заданном фрагменте a[5:], а затем удалит ее?

Это так, это не будет операция на месте, так как мы используем фрагменты здесь.

Но

a = [1,2,3,4,5,6,7,8,9,0]
for i in range(5,len(a),-1):
    del a[i]

Эта операция выполняется на месте, поскольку мы не используем срезы.

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

Но я проверил, и это наоборот:

%%timeit
a = [x for x in range(1000)]
del a[500:]
> 45.8 µs ± 3.05 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)
%%timeit
a = [x for x in range(1000)]
for i in range(999,499,-1):
    del a[i]
> 92.9 µs ± 3.24 µs per loop (mean ± std. dev. of 7 runs, 10000 loops each)

Теперь, если мы предположим, что del a[500:] сначала создает срез, а затем удаляет, тогда это не совсем на месте, и использование цикла for для той же задачи на месте? Но тогда почему циклу требуется больше времени для выполнения задачи?

Так же, если на всякий случай предположить, что как-то они оба на месте и del a[500:] не создает слайс-копию a по этому индексу, а del напрямую идет по индексу 500 и рекурсивно удаляет элементы, то что именно a[500:] в этом утверждение? Просто сказать, откуда del удалять?

Если да, то это не срез?

Я сослался на несколько ссылок, таких как приведенная ниже, чтобы найти ответ на этот вопрос, но я не очень ясно понимаю ни одно из объяснений, посвященных исключительно операциям in-place.

Что именно делает del?


person Zenquiorra    schedule 26.07.2020    source источник


Ответы (2)


тогда что именно a[500:] в этом утверждении? Просто сказать, откуда del удалять?

да.

Тогда не создаст ли он копию, т.е. сначала новый объект из списка для данного слайса, а потом удалит его?

Копия не создается. Вот почему del является ключевым словом, а не встроенной функцией: это специальный синтаксис, который по-разному интерпретирует часть a[5:] в контексте. (Если бы это была функция, то перед вызовом функции нужно было бы вычислить a[5:]; кроме того, функция не могла бы работать, потому что ей было бы предоставлено отдельное значение, а не знание какой исходный объект оперировать.)

Но я проверил, и они оба занимают почти одинаковое время:

for i in range(500,1000,-1):

Осторожный; это пустой цикл. Предположительно, вы имели в виду for i in range(1000, 500, -1), но это тоже неверно - должно быть for i in range(999, 499, -1), чтобы получить соответствующее поведение. И теперь вы понимаете, почему для del поддерживается синтаксис slice :)

В любом случае, я понятия не имею о твоих результатах тайминга.

person Karl Knechtel    schedule 26.07.2020

Важно понимать, что это две разные вещи:

del name

а также

del container[index]

Первый удаляет имя из текущего пространства имен. del не работает с произвольными выражениями и не удаляет объекты, удаляет имена:

>>> del [1,2,3]
  File "<stdin>", line 1
SyntaxError: cannot delete literal
>>> del list()
  File "<stdin>", line 1
SyntaxError: cannot delete function call

Однако,

del container[index]

Будет вызывать

container.__delitem__(index)

Который может делать все, что вы хотите, он может быть на месте или нет. Или ничего не делать...

С другой стороны

container[index]

Вызывает

container.__getitem__(index)

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

Возможно, это поучительно:

>>> class Container:
...     def __getitem__(self, item):
...         print('Container.__getitem__ called with', item)
...     def __delitem__(self, item):
...         print('Container.__delitem__ called with', item)
...
>>> container = Container()
>>> container[:]
Container.__getitem__ called with slice(None, None, None)
>>> del container[:]
Container.__delitem__ called with slice(None, None, None)
>>> del container

Обратите внимание, del container тоже не вызывает...

person juanpa.arrivillaga    schedule 26.07.2020