Когда Del полезен в Python? - PullRequest
326 голосов
/ 27 мая 2011

Я не могу придумать причину, по которой python нуждается в ключевом слове del (и большинство языков, похоже, не имеют аналогичного ключевого слова).Например, вместо удаления переменной можно просто присвоить ей None.А при удалении из словаря можно добавить метод del.

Есть ли причина сохранять del в python или это пережиток дней Python перед сборкой мусора?

Ответы [ 19 ]

442 голосов
/ 27 мая 2011

Во-первых, вы можете исключить другие вещи, кроме локальных переменных

del list_item[4]
del dictionary["alpha"]

Оба из которых должны быть явно полезными. Во-вторых, использование del в локальной переменной делает намерение более понятным. Для сравнения:

del foo

до

foo = None

В случае del foo я знаю, что цель состоит в том, чтобы удалить переменную из области видимости. Не ясно, что foo = None делает это. Если кто-то просто назначил foo = None, я мог бы подумать, что это мертвый код. Но я сразу знаю, что пытался сделать кто-то, кто кодирует del foo.

148 голосов
/ 27 мая 2011

Эта часть того, что делает del (из Python Language Reference ):

Удаление имени удаляет привязку этого имени из локального или глобальногопространство имен

Присвоение None имени не приводит к удалению привязки имени из пространства имен.

(я полагаю, что могут возникнуть некоторые споры о том, является ли удаление привязки именина самом деле полезно , но это другой вопрос.)

38 голосов
/ 03 июня 2015

Одно место, которое я нашел del, полезно очищать внешние переменные для циклов:

for x in some_list:
  do(x)
del x

Теперь вы можете быть уверены, что x будет неопределенным, если вы используете его вне цикла for.

16 голосов
/ 27 мая 2011

Существует конкретный пример того, когда вы должны использовать del (могут быть и другие, но я знаю об этом один раз), когда вы используете sys.exc_info() для проверки исключения. Эта функция возвращает кортеж, тип возникшего исключения, сообщение и трассировку.

Первые два значения обычно достаточны для диагностики ошибки и воздействия на нее, но третье содержит весь стек вызовов между местом возникновения исключения и местом его обнаружения. В частности, если вы делаете что-то вроде

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    if something(exc_value):
        raise

traceback, tb заканчивается в локальных элементах стека вызовов, создавая циклическую ссылку, которая не может быть собрана сборщиком мусора. Таким образом, важно сделать:

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    del tb
    if something(exc_value):
        raise

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

exc_type, exc_value = sys.exc_info()[:2]

Чтобы избежать всего этого вместе.

15 голосов
/ 28 июня 2016

Удаление переменной отличается от ее установки на None

Удаление имен переменных с помощью del, вероятно, используется редко, но это не может быть достигнуто тривиально без ключевого слова.Если вы можете создать имя переменной, написав a=1, хорошо, что вы теоретически можете отменить это, удалив.

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

Вы можете удалить атрибуты экземпляра класса

Python позволяет написать что-то вроде:

class A(object):
    def set_a(self, a):
        self.a=a
a=A()
a.set_a(3)
if hasattr(a, "a"):
    print("Hallo")

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

del a.a
14 голосов
/ 14 декабря 2012

Просто еще одна мысль.

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

9 голосов
/ 03 июня 2015

Использование «del» в явном виде также лучше, чем присвоение переменной None.Если вы попытаетесь удалить переменную, которая не существует, вы получите ошибку времени выполнения, но если вы попытаетесь установить переменную, которая не существует, в None, Python автоматически установит новую переменную в None, оставив переменнуюхотел удалить, где это было.Так что Del поможет вам поймать ваши ошибки раньше

7 голосов
/ 19 апреля 2016

Чтобы добавить несколько пунктов к ответам выше: del x

Определение x указывает r -> o (ссылка r, указывающая на объект o), но del x изменяется r, а не o.Это операция над ссылкой (указателем) на объект, а не на объект, связанный с x.Здесь ключевое значение имеет различение между r и o.

  • Удаляет его из locals().
  • Удаляет его из globals(), если x принадлежит там.
  • Удаляет его из фрейма стека (физически удаляет из него ссылку, но сам объект находится в пуле объектов, а не в фрейме стека).
  • Удаляет его из текущей области.Очень полезно ограничить диапазон определения локальной переменной, что в противном случае может вызвать проблемы.
  • Это больше касается объявления имени, а не определения содержимого.
  • Это влияет на то, гдеx принадлежит, а не x указывает на.Единственное физическое изменение в памяти - это.Например, если x находится в словаре или списке, оно (как ссылка) удаляется оттуда (и не обязательно из пула объектов).В этом примере словару, которому он принадлежит, является кадр стека (locals()), который перекрывается с globals().
6 голосов
/ 26 сентября 2014

Принудительное закрытие файла после использования numpy.load:

Возможно, использование ниши, но я нашел это полезным при использовании numpy.load для чтения файла. Время от времени я обновлял файл, и мне нужно было скопировать файл с таким же именем в каталог.

Я использовал del, чтобы освободить файл и разрешить мне копировать в новый файл.

Примечание. Я хочу отказаться от диспетчера контекста with, поскольку я играл с графиками в командной строке и не хотел много нажимать клавишу Tab!

См. этот вопрос.

6 голосов
/ 08 ноября 2016

del часто встречается в __init__.py файлах. Любая глобальная переменная, определенная в файле __init__.py, автоматически «экспортируется» (она будет включена в from module import *). Один из способов избежать этого - определить __all__, но это может запутаться, и не все его используют.

Например, если у вас был код в __init__.py как

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

Тогда ваш модуль экспортирует имя sys. Вместо этого вы должны написать

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

del sys
...