Другие ответы рассматривают это с технической точки зрения (например, как лучше всего изменить список), но я бы сказал, что (намного) более важная причина, по которой люди рекомендуют, например, нарезку, заключается в том, что это не изменить исходный список.
Причина этого, в свою очередь, в том, что обычно список откуда-то брался. Если вы измените его, вы можете неосознанно вызвать серьезные и трудно обнаруживаемые побочные эффекты, которые могут вызвать ошибки в других частях программы. Или даже если вы не вызовете ошибку немедленно, вы сделаете свою программу в целом более трудной для понимания, анализа и отладки.
Например, выражения списков/генераторов хороши тем, что они никогда не мутируют исходный список, который они передают:
[x for x in lst if x != "foo"] # creates a new list
(x for x in lst if x != "foo") # creates a lazy filtered stream
Это, конечно, часто более затратно (с точки зрения памяти), потому что создает новый список, но программа, использующая этот подход, математически чище и проще для понимания. А с ленивыми списками (генераторами и генераторными выражениями) исчезнут даже накладные расходы памяти, а вычисления выполняются только по требованию; см. http://www.dabeaz.com/generators/ для отличного введения. И вы не должны слишком много думать об оптимизации при разработке своей программы (см. evil">https://softwareengineering.stackexchange.com/questions/80084/is-premature-optimization-really-the-root-of-all-evil). Кроме того, удаление элемента из списка довольно затратно, если только это не связанный список (чем не является Python list
; для связанного списка см. collections.deque
).
На самом деле, функции без побочных эффектов и неизменяемые структуры данных являются основой Функционального программирования, очень мощного метода программирования. парадигма.
Тем не менее, при определенных обстоятельствах допустимо изменять существующую структуру данных (даже в FP, если язык позволяет это), например, если он создан локально или скопирован из ввода функции:
def sorted(lst):
ret = list(lst) # make a copy
# mutate ret
return ret
— эта функция кажется чистой функцией извне, потому что она не изменяет свои входные данные (а также зависит только от своих аргументов и ни от чего другого (т. е. у нее нет (глобального) состояния), что является еще одним требованием для того, чтобы что-то было a Pure Функция).
Так что, пока вы знаете, что делаете, del
ни в коем случае не плохо; но используйте любую мутацию данных с особой осторожностью и только тогда, когда это необходимо. Всегда начинайте с возможно менее эффективного, но более правильного и математически элегантного кода.
...и изучите функциональное программирование :)
P.S. обратите внимание, что del
также можно использовать для удаления локальных переменных и, таким образом, устранения ссылок на объекты в памяти, что часто полезно для любых целей, связанных с сборщиком мусора.
Ответ на второй вопрос:
Что касается второй части вашего вопроса о del
полном удалении объектов — это не так: на самом деле в Python невозможно даже указать интерпретатору/VM удалить объект из памяти, потому что Python — это язык со сборщиком мусора (например, Java, C#, Ruby, Haskell и т. д.), и именно среда выполнения решает, что и когда удалять.
Вместо этого то, что del
делает при вызове переменной (в отличие от ключа словаря или элемента списка), выглядит следующим образом:
del a
заключается в том, что он только удаляет локальную (или глобальную) переменную, а не то, на что указывает переменная (каждая переменная в Python содержит указатель/ссылку на свое содержимое, а не само содержимое ). Фактически, поскольку локальные и глобальные переменные хранятся в виде словаря под капотом (см. locals()
и globals()
), del a
эквивалентно:
del locals()['a']
или del globals()['a']
применительно к глобальному.
так что если у вас есть:
a = []
b = a
вы создаете список, сохраняете ссылку на него в a
, а затем делаете еще одну копию этой ссылки и сохраняете ее в b
, не копируя/касаясь самого объекта списка. Следовательно, эти два вызова влияют на один и тот же объект:
a.append(1)
b.append(2)
# the list will be [1, 2]
тогда как удаление b
никоим образом не связано с прикосновением к тому, на что указывает b
:
a = []
b = a
del b
# a is still untouched and points to a list
Кроме того, даже когда вы вызываете del
для атрибута объекта (например, del self.a
), вы все равно фактически изменяете словарь self.__dict__
точно так же, как вы фактически изменяете locals()
/globals()
, когда делаете del a
.
P.S. как Свен Маркнах указал, что del locals()['a']
на самом деле не удаляет локальную переменную a
внутри функции, что правильно. Вероятно, это связано с тем, что locals()
возвращает копию реальных локальных файлов. Тем не менее, ответ по-прежнему остается в силе.
person
Erik Kaplun
schedule
28.04.2014
del
, вероятно, неплохо, но наличие синтаксисаdel
для удаления списковых индексов является неудобной особенностью языка, как иlen(..)
, оба из которых раздражают новичков, которые жалуются на то, что он идет против зерно других популярных языков без четкого обоснования. - person Evgeni Sergeev   schedule 28.04.2014len
зачем иметьlist.length
,str.length
,array.length
и т. д., если у вас может быть одна функция, которая даст вам длину любого объекта, который может иметь ее? (т. е. любой объект с__len__
)? - person Two-Bit Alchemist   schedule 28.04.2014len
, о котором кто-то упомянул, — этоmap(len, listoflists)
, поэтому он имеет свое место. Я не понимаю, почему у нас не должно быть метода.size()
и для встроенных структур данных. Встроенныйlen(..)
выполняет небольшую проверку после вызова.__len__()
объекта, но он кажется скорее параноидальным, чем полезным stackoverflow.com/questions/496009/ - person Evgeni Sergeev   schedule 29.04.2014len
занимается Python дольше, чем это было разумно возможно реализовать. Я предполагаю, что это можно было бы сделать в Py3k, но Python не имеет смешного количества глобальных встроенных модулей, таких какlen
, и их нужно урезать. - person Two-Bit Alchemist   schedule 29.04.2014.__len__()
не должно быть магией. (Он должен называться.size()
, аlen(x)
вызоветx.size()
, или вы можете просто использоватьx.size()
.) - person Evgeni Sergeev   schedule 29.04.2014del
иappend
. - person Erik Kaplun   schedule 30.04.2014