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

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

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

Ответ 1

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

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

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

del foo

к

foo = None

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

Ответ 2

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

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

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

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

Ответ 3

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

for x in some_list:
  do(x)
del x

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

Ответ 4

Существует конкретный пример того, когда вы должны использовать 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(), например, с помощью метаклассической магии, трассировка полезна, поэтому вам нужно убедиться, что вы ее очистите, прежде чем вы сможете покинуть обработчик исключений. Если вам не нужна трассировка, вы должны удалить ее немедленно или просто:

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

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

Ответ 5

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

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

В некоторых случаях упрощение отладки может быть проще, так как попытка доступа к удаленной переменной повысит значение 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

Ответ 6

Просто другое мышление.

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

Ответ 7

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

Ответ 8

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

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

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

Ответ 9

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

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

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

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

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

Ответ 10

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

Ответ 11

В качестве примера того, для чего может использоваться 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)

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

Ответ 12

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

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

Ответ 13

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

Ответ 14

Еще одно использование ниши: в 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 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 более разумного управления объектами.

Ответ 15

Команда "del" очень полезна для управления данными в массиве, например:

elements = ["A", "B", "C", "D"]
# Remove first element.
del elements[:1]
print(elements)

Выход:

['B', 'C', 'D']

Ответ 16

Я обнаружил, что del полезна для псевдо-ручного управления памятью при обработке больших данных с помощью Numpy. Например:

for image_name in large_image_set:
    large_image = io.imread(image_name)
    height, width, depth = large_image.shape
    large_mask = np.all(large_image == <some_condition>)
    # Clear memory, make space
    del large_image; gc.collect()

    large_processed_image = np.zeros((height, width, depth))
    large_processed_image[large_mask] = (new_value)
    io.imsave("processed_image.png", large_processed_image)

    # Clear memory, make space
    del large_mask, large_processed_image; gc.collect()

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

Ответ 17

Как-то мне пришлось использовать:

del serial
serial = None

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

serial = None

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

Ответ 18

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

Ответ 19

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