Я использую Spyder для исследовательского анализа данных, а не для производственного кода. Мне нравится думать о своем сценарии как о последовательности основных разделов. В конце каждого раздела я хочу удалить временные объекты, чтобы обозреватель переменных в Spyder не был слишком перегружен. Однако существующие объекты зависят от потока управления через код. Если у меня есть только один оператор «del» в конце каждого раздела для удаления всех объектов, которые могут появиться независимо от потока управления через код, я получаю NameError
для тех объектов, которые не были созданы.
Есть ли простой однострочник, который я могу использовать, похожий на del a,b,c,d
, но не выдающий ошибку, если некоторые переменные не существуют? Мне нужна короткая строка, потому что я не хочу отвлекать внимание от основных функций кода.
На мой взгляд, блок try/Exception — это многострочная управляющая структура, которая вносит в код слишком много когнитивного шума. Что-то вроде следующего кажется незаконным, и похоже, что однострочный текст не может состоять из оператора if внутри цикла for:
# Syntax error at the "if"
for vName in ['gbCluster']: if vName in locals(): del locals()[vName]
# Works without "if"
for vName in ['gbCluster']: del locals()[vName]
Не по делу, но вы не должны изменять locals(). Вместо этого используйте globals()
.
@wjandrea: Спасибо! Ваш комментарий побудил меня узнать, что пространство имен REPL является глобальным, как описано здесь
@Ry: Спасибо! Я не полагаю, что можно избежать цикла for для извлечения нескольких переменных/объектов? Послесловие: Кажется невозможным. Я думаю, переменная цикла сохранится без дополнительного del
. Ничего страшного. Вы хотели опубликовать свой комментарий в качестве ответа?
{globals().pop(k, None) for k in 'abcd'}
не оставит переменную цикла в пространстве имен.
«В конце каждого раздела я хочу удалить временные объекты, чтобы проводник переменных в Spyder не был слишком перегружен». Рассматривали ли вы возможность просто использовать ряд функций? Передавайте переменные, которые вы хотите сохранить, из одного блока в другой в качестве параметров (или глобальных переменных), а остальные определите в области действия функции.
@tobias_k: Я обнаружил, что для исследовательского анализа данных я часто переделываю код, поэтому мне бы хотелось избежать дополнительной постоянной перенастройки сигнатур функций и вызовов функций.
@wim: Спасибо! Отлично! (Не так хорошо, как команда без ошибок del
, но такой команды не существует). Стоит ли публиковать в качестве ответа?
Я принципиально не отвечаю на вопросы, требующие остроты. И я думаю, что ответ, который вы приняли, в любом случае намного лучше.
@wim: ОК. Что ж, вот шаблон кода, который я использовал на основе вашего примера: _ = {globals().pop(vNm,None) for vNm in ('cat','horse') }
. Присвоение _
скрывает вывод Spyder Explorer.
Что-то вроде
for name in [n for n in somelist if n in someplace]: del someplace[name]
должно сработать
Это работает, если someplace
является существующей dict
, но не для переменных с произвольными именами (globals()
можно использовать в некоторых случаях, но locals()
будет работать только в глобальной области видимости, где это эквивалентно globals()
).
Я знаю, я оставляю эту часть открытой для заполнения ОП. Вопрос был больше о том, как написать однострочный текст, чем о том, как удалять переменные.
Спасибо, вот шаблон кода, который я нашел работающим: for vNm in [ ifNm for ifNm in ['dog','cat','ifKeep1innerSpc'] if ifNm in globals() ]: del globals()[vNm]
. Это действительно укрепило мое шаткое понимание понимания списков.
да, это точно такой же шаблон кода, как тот, который я предложил
Используйте функцию! Вы можете передать пространство имен (dict), из которого вы хотите удалить имена (ключи), и функция сможет выполнить тяжелую работу по удалению и игнорированию ошибок. Затем вы можете поместить функцию в модуль для повторного использования.
Кстати, имена, которые вы хотите удалить, являются глобальными, а не локальными как таковыми (и в любом случае вам не следует изменять locals()).
def del_keys_noerror(d, *keys):
for key in keys:
try:
del d[key]
except KeyError:
pass # Ignore keys that are already absent
Например:
a = False
if a:
b = 0
del_keys_noerror(globals(), 'a', 'b')
Результат: a
удаляется.
P.S. Я мог бы добавить регистрацию в журнал, когда имя уже неопределенно или успешно удалено, на всякий случай, если вам нужно отладить функцию.
@wjandrea: Спасибо. Я думаю, что это может быть наиболее практичным на данный момент. Другие ответы и комментарии демонстрируют умные и гибкие акробатические трюки, которые помогли мне с Python, но вызов функции для удаления из глобальных переменных требует наименьшего количества накладных расходов в основной части кода.
Он не удаляет глобальные переменные (имена по-прежнему будут существовать), но если ваша цель — просто освободить память объектов, на которые они ссылаются, существует умная однострочная программа, позволяющая установить для всех таких имен значение None
(поэтому ссылка на name по-прежнему будет работать, но будет содержать None
, а не какой-то огромный объект, который там раньше был):
globals().update(dict.fromkeys(("names", "to", "clear")))
dict.fromkeys
принимает итерацию ключей и быстро создает простой dict
с этими ключами, сопоставляя их все с None
(если вы передадите второй аргумент, он будет использовать его вместо этого). globals().update(...)
затем массово обновляет словарь глобальных переменных. На самом деле это создаст переменные, если они еще не существовали (со значением None
), но если вас беспокоит освобождение памяти, а не очистка глобального пространства имен от лишних имен (обычно это не важно), это работает так же хорошо (и, вероятно, быстрее). для загрузки, поскольку он выполняет обе операции массово на уровне C).
Спасибо, но я вообще-то пытаюсь минимизировать загрязнение в Spyder's Variable Explorer. Я храню много DataFrame, поэтому все промежуточные переменные, используемые для их построения, должны быть del
.
Я не знаком со Spyder – важно ли, чтобы это была одна строка, чтобы ее можно было получить из поиска по истории, или…? В любом случае,
globals().pop(vName, None)
в вашем цикле — это типичный способ удалить ключ, только если он существует.