Existe uma maneira de excluir variáveis ​​criadas, funções, etc. da memória do interpretador?

114

Estou procurando a resposta precisa para essa pergunta há alguns dias, mas não encontrei nada de bom. Não sou um novato completo em programação, mas ainda não estou no nível intermediário.

Quando estou no shell do Python, digito: dir()e posso ver todos os nomes de todos os objetos no escopo atual (bloco principal), há 6 deles:

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__']

Então, quando estou declarando uma variável, por exemplo x = 10, ela adiciona automaticamente a essa lista de objetos no módulo integrado e dir(), quando eu digito dir()novamente, ela mostra agora:

['__builtins__', '__doc__', '__loader__', '__name__', '__package__', '__spec__', 'x']

O mesmo vale para funções, classes e assim por diante.

Como excluo todos esses novos objetos sem apagar o padrão 6 que estava disponível no início?

Eu li aqui sobre "limpeza de memória", "limpeza do console", que apaga todo o texto da janela do prompt de comando:

>>> import sys
>>> clear = lambda: os.system('cls')
>>> clear()

Mas tudo isso não tem nada a ver com o que estou tentando alcançar, não limpa todos os objetos usados.

Funghorn
fonte
2
Por que você acha que precisa fazer isso ou só está perguntando por curiosidade?
PM 2Ring
Eu simplesmente não sabia que havia uma delfunção lá fora. Estou começando a aprender Python e frequentemente tenho que experimentar no shell, então nomes de variáveis ​​padrão como xou ymuitas vezes já estão em uso e reiniciar o shell leva mais 15 segundos para fazer (eu tenho um laptop muito, muito antigo agora). Então, eu queria encontrar uma maneira de limpar a memória do Python mais rápido.
funghorn
1
Ah. FWIW, delnão é exatamente uma função, portanto, não (e ). É uma palavra-chave que introduz uma instrução del. Claro, como ele realmente exclui um objeto pode envolver funções, mas isso é outra história ...
PM 2Ring
Ao experimentar os nomes de shell como xou ynão devem ser usados, a menos que você os esteja usando. Ou a menos que você faça algo bobo como from _somemodule_ import *, então você terá todo tipo de lixo bagunçando o lugar. :)
PM 2Ring
1
Pesquisei no Google meu caminho para esta pergunta e agora estou me perguntando - por que não posso simplesmente reiniciar o kernel e executar novamente o script do início se quero excluir todas as variáveis ​​e funções mesmo assim?
vagabundo de

Respostas:

159

Você pode excluir nomes individuais com del:

del x

ou você pode removê-los do globals()objeto:

for name in dir():
    if not name.startswith('_'):
        del globals()[name]

Este é apenas um exemplo de loop; ele apaga defensivamente apenas nomes que não começam com sublinhado, assumindo (não sem razão) que você usou apenas nomes sem sublinhado no início do seu interpretador. Em vez disso, você poderia usar uma lista codificada de nomes para manter (lista de permissões) se realmente quisesse ser minucioso. Não há nenhuma função embutida para fazer a limpeza para você, a não ser apenas sair e reiniciar o interpretador.

Os módulos que você importou ( import os) permanecerão importados porque são referenciados por sys.modules; as importações subsequentes reutilizarão o objeto de módulo já importado. Você simplesmente não terá uma referência a eles em seu namespace global atual.

Martijn Pieters
fonte
Bem, devo dizer que startswith('_')parece bastante ingênuo. Se alguém é inteligente o suficiente para escrever _foo=42ou até mesmo __foo__=42, como podemos excluí-los? Existe uma maneira de obter nomes de propriedades de módulo padrão programaticamente?
georg
2
@georg: Codifiquei o loop defensivamente. Você terá que codificar uma lista inicial de nomes para manter se quiser fazer melhor.
Martijn Pieters
Então, de jeito nenhum? Meu pensamento era dir(ModuleType()), mas ele só retorna doce name.
georg
1
@georg: não; o namespace global do interpretador varia de versão para versão também, e não há uma maneira infalível (que eu conheça) de enumerar o que estava lá quando você abriu o interpretador em um estágio posterior .
Martijn Pieters
1
As funções e classes @nakE são apenas objetos como qualquer outro. Eles não são especiais; use uma lista de permissões ou verifique o tipo de objeto de que você precisa para preservar classes e funções.
Martijn Pieters
67

Sim. Existe uma maneira simples de remover tudo no iPython. No console do iPython, basta digitar:

%reset

Então, o sistema irá pedir para você confirmar. Pressione y. Se você não quiser ver este prompt, basta digitar:

%reset -f

Isso deve funcionar ..

EyesBear
fonte
1
Mais uma vez, por que essa não é a melhor resposta?
myradio
11
@myradio Porque é irrelevante para todos que não usam IPython , e também não responde à pergunta; a questão pergunta como excluir referências de objetos globais, não redefinir o conteúdo do shell IPython .
Andreas
17

Você pode usar o coletor de lixo Python:

import gc
gc.collect()
Fardin
fonte
6
Ei @Fardin! obrigado! Sua resposta fez o trabalho e salvou meu dia! Mas antes de gc.collect () eu fiz del (variável).
Gmosy Gnaq
9

Se você está em um ambiente interativo como Jupyterou ipythonpode estar interessado em limpar os variáveis ​​indesejados, se eles estiverem ficando pesados.

A magia-comandos reset e reset_selectiveé vailable em sessões python interativos, como ipythoneJupyter

1) reset

reset Redefine o namespace removendo todos os nomes definidos pelo usuário, se chamados sem argumentos.

ine os outparâmetros especificam se você deseja liberar os caches de entrada / saída. O histórico do diretório é limpo com o dhistparâmetro.

reset in out

Outro interessante é arrayque remove apenas Arrays numpy:

reset array

2) reset_selective

Redefine o namespace removendo nomes definidos pelo usuário. O histórico de entrada / saída é deixado para o caso de você precisar deles.

Exemplo de matriz limpa:

In [1]: import numpy as np
In [2]: littleArray = np.array([1,2,3,4,5])
In [3]: who_ls
Out[3]: ['littleArray', 'np']
In [4]: reset_selective -f littleArray
In [5]: who_ls
Out[5]: ['np']

Fonte: http://ipython.readthedocs.io/en/stable/interactive/magics.html

user1767754
fonte
6

Isso funcionou para mim.

Você precisa executá-lo duas vezes uma vez para globais seguidos por locais

for name in dir():
    if not name.startswith('_'):
        del globals()[name]

for name in dir():
    if not name.startswith('_'):
        del locals()[name]
Viswa
fonte
4

Na verdade, o python irá recuperar a memória que não está mais em uso. Isso é chamado de coleta de lixo, que é um processo automático em python. Mesmo assim, se você quiser fazer isso, pode excluí-lo por del variable_name. Você também pode fazer isso atribuindo a variável aNone

a = 10
print a 

del a       
print a      ## throws an error here because it's been deleted already.

A única maneira de realmente recuperar a memória de objetos Python não referenciados é por meio do coletor de lixo. A palavra-chave del simplesmente desassocia um nome de um objeto, mas o objeto ainda precisa ser coletado como lixo. Você pode forçar o coletor de lixo a ser executado usando o módulo gc, mas isso é quase certamente uma otimização prematura, mas tem seus próprios riscos. Usar delnão tem efeito real, pois esses nomes teriam sido excluídos ao sair do escopo de qualquer maneira.

d-coder
fonte
De fato. Claro, ao trabalhar no namespace global do interpretador, os nomes não vão sair do escopo, mas e daí. :) Eu acho que é também vale a pena mencionar que o que acontece com a memória usada por objetos que foram lixo coletado é dependente de implementação, mas na maioria das implementações Python a memória gc'ed meramente volta para a piscina Python, é não voltou para o OS até o programa terminar.
PM 2Ring de
@ PM2Ring LOL :) Acho que sim. De onde você se refere a python?
d-coder
2
Observe que no CPython o GC é necessário apenas para quebrar os ciclos de referência. Se nenhuma referência permanecer, um objeto é imediatamente removido da memória. Então del , tem um efeito real aqui.
Martijn Pieters
@MartijnPieters, insta-removed? É um termo técnico? :)
Eryk Sun
2
@eryksun: sim, conforme definido pela RFC 4042-bis2, é claro! :-P
Martijn Pieters