Когда del полезен в python?

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

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

17 ответов


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

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

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

del foo

to

foo = None

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


есть эта часть того, что del делает (с Ссылка На Язык Python):

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

назначение None to a name не удаляет привязку имени из пространства имен.

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


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

for x in some_list:
  do(x)
del x

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


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

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


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

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

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

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

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

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

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

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


удаление переменной отличается от ее установки в 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

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

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

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

примечание Я хочу избежать with context manager, когда я играл с сюжетами в команде line и не хотел много нажимать tab!

посмотреть этой вопрос.


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


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

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

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

когда del полезен в python?

вы можете использовать его для удаления одного элемента массива вместо синтаксиса среза x[i:i+1]=[]. Это может быть полезно, если например вы находитесь в os.walk и хотите удалить элемент в каталоге. Я бы не счел ключевое слово полезным для этого, хотя, так как можно просто сделать [].remove(index) метод (.remove метод на самом деле search-and-remove-first-instance-of-value).


что del может использоваться для, Я нахожу это полезным Я ситуации, как это:

def f(a, b, c=3):
    return '{} {} {}'.format(a, b, c)

def g(**kwargs):
    if 'c' in kwargs and kwargs['c'] is None:
        del kwargs['c']

    return f(**kwargs)

# g(a=1, b=2, c=None) === '1 2 3'
# g(a=1, b=2) === '1 2 3'
# g(a=1, b=2, c=4) === '1 2 4'

эти две функции могут быть в разных пакетах/модули и программисту не нужно знать, какой аргумент значение по умолчанию c на f на самом деле есть. Поэтому, используя kwargs в сочетании с del, вы можете сказать:" я хочу значение по умолчанию на c", установив его в None (или в этом случае также оставьте его).

вы могли бы сделать то же самое с что-то вроде:

def g(a, b, c=None):
    kwargs = {'a': a,
              'b': b}
    if c is not None:
        kwargs['c'] = c

    return f(**kwargs)

однако я нахожу предыдущий пример более сухим и элегантным.


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

Я думаю, что одна из причин того, что del имеет свой собственный синтаксис, заключается в том, что замена его функцией может быть трудной в определенных случаях, учитывая, что она работает с привязкой или переменной, а не со значением, на которое она ссылается. Таким образом, если версия функции del должна быть создана, необходимо будет передать контекст. дель фу должен был стать globals ().удалить ('foo') или locals ().удалить ('foo'), который становится грязным и менее читаемым. Тем не менее, я говорю, что избавиться от del было бы хорошо, учитывая его, казалось бы, редкое использование. Но удаление языковых функций / недостатков может быть болезненным. Возможно, python 4 удалит его:)


еще одна ниша использования : В pyroot С ROOT5 или ROOT6 " del " может быть полезно удалить объект python, который ссылается на более не существующий объект c++. Это позволяет динамическому поиску pyroot найти объект с идентичным именем C++ и привязать его к имени python. Таким образом, вы можете иметь такой сценарий, как:

import ROOT as R
input_file = R.TFile('inputs/___my_file_name___.root')
tree = input_file.Get('r')
tree.Draw('hy>>hh(10,0,5)')
R.gPad.Close()
R.hy # shows that hy is still available. It can even be redrawn at this stage.
tree.Draw('hy>>hh(3,0,3)') # overwrites the C++ object in ROOT's namespace
R.hy # shows that R.hy is None, since the C++ object it pointed to is gone
del R.hy
R.hy # now finds the new C++ object

Надеюсь, эта ниша будет закрыта с более разумным управлением объектами ROOT7.


однажды мне пришлось использовать:

del serial
serial = None

потому что используя только:

serial = None

не отпустил последовательный порт достаточно быстро, чтобы сразу открыть его снова. Из этого урока я понял, что del действительно означало: "GC это сейчас! и подождите, пока это не будет сделано", и это действительно полезно во многих ситуациях. Конечно, у вас может быть system.gc.del_this_and_wait_balbalbalba(obj).


del является эквивалентом "unset" на многих языках и как перекрестная точка отсчета, переходящая с другого языка на python.. люди склонны искать команды, которые делают то же самое, что они делали на своем родном языке... также установка var в "" или none на самом деле не удаляет var из области .. он просто опустошает его значение имя самого вара все еще хранилось в памяти...почему?!? в сценарии с интенсивной памятью..держать мусор за его просто нет и в любом случае...каждый язык там имеет некоторую форму функции var" unset/delete"..почему не питон?


каждый объект в python имеет идентификатор, тип, счетчик ссылок, связанный с ним, когда мы используем del, счетчик ссылок уменьшается, когда счетчик ссылок становится нулевым, это потенциальный кандидат для сбора мусора. Это отличает del по сравнению с установкой идентификатора None. В более позднем случае это просто означает, что объект просто оставлен диким (пока мы не выйдем из области, в этом случае количество уменьшается), и просто теперь идентификатор указывает на какой-то другой объект(область памяти).