Come posso cancellare tutte le variabili nel mezzo di uno script Python?


88

Sto cercando qualcosa di simile a "clear" in Matlab: un comando / funzione che rimuove tutte le variabili dallo spazio di lavoro, rilasciandole dalla memoria di sistema. Esiste una cosa del genere in Python?

EDIT: voglio scrivere uno script che a un certo punto cancella tutte le variabili.


2
Sarà utile se hai cambiato il titolo in qualcosa del tipo "Come posso cancellare tutte le variabili nel mezzo di uno script Python?" per future ricerche sull'argomento, perché "Come riavviare la finestra di comando in Python?" non ha nulla a che fare con ciò che stai effettivamente chiedendo.
Sam Dolan

Potete fornire un possibile contesto in cui ciò abbia senso?
S.Lott

2
Sembra un altro caso in cui si cerca di spostare le abitudini di codifica dal loro ambiente nativo a uno in cui non hanno alcun senso.
Glenn Maynard

Se sei solo preoccupato per alcuni oggetti enormi (immagini o altri enormi array), potresti delaverli quando hai finito. Se sei semplicemente preoccupato che lo spazio dei nomi sia disordinato, dovresti probabilmente riconsiderare il tuo design usando così tanti nomi. Ad esempio, per una serie di trasformazioni di immagini, probabilmente non è necessario mantenere ogni passaggio intermedio.
Nick T

4
@ S.Lott: analisi scientifica esplorativa in una console. È comune ritrovarsi con molte variabili indesiderate (dopo aver provato le cose e quindi aver deciso che non è un percorso rilevante). Ma in questo caso, la risposta di John La Rooy è la più appropriata.
nought101

Risposte:


70

La seguente sequenza di comandi rimuove ogni nome dal modulo corrente:

>>> import sys
>>> sys.modules[__name__].__dict__.clear()

Dubito che tu voglia davvero farlo, perché "ogni nome" include tutti i built-in, quindi non c'è molto che puoi fare dopo una tale cancellazione totale. Ricorda, in Python non esiste davvero una cosa come una "variabile" - ci sono oggetti , di molti tipi (inclusi moduli, funzioni, classi, numeri, stringhe, ...) e ci sono nomi , legati a oggetti; quello che fa la sequenza è rimuovere ogni nome da un modulo (gli oggetti corrispondenti scompaiono se e solo se ogni riferimento ad essi è stato appena rimosso).

Forse vuoi essere più selettivo, ma è difficile indovinare esattamente cosa intendi a meno che tu non voglia essere più specifico. Ma, solo per fare un esempio:

>>> import sys
>>> this = sys.modules[__name__]
>>> for n in dir():
...   if n[0]!='_': delattr(this, n)
... 
>>>

Questa sequenza lascia da soli i nomi privati ​​o magici, incluso il __builtins__nome speciale che ospita tutti i nomi incorporati. Quindi, i built-in funzionano ancora, ad esempio:

>>> dir()
['__builtins__', '__doc__', '__name__', '__package__', 'n']
>>> 

Come puoi vedere, anche il nome n(la variabile di controllo in quella for) rimane inalterato (poiché viene ricollegato nella forclausola ogni volta), quindi potrebbe essere meglio nominare quella variabile di controllo _, ad esempio, per mostrare chiaramente "è special "(inoltre, nell'interprete interattivo, il nome _viene ricollegato comunque dopo ogni espressione completa immessa al prompt, al valore di quell'espressione, quindi non rimarrà a lungo ;-).

Comunque, una volta che avete determinato esattamente che cosa è che si vuole fare, non è difficile definire una funzione per lo scopo e metterlo nel file di start-up (se lo vuoi solo in sessioni interattive) o un file sito da personalizzare ( se lo vuoi in ogni script).


2
Beh potresti sempre tenere una copia del dizionario originale all'avvio e poi rimuovere i nomi che sono stati aggiunti;) Tuttavia penso che questo sia un chiaro abuso del sistema dinamico, e non riesco a pensare a una situazione non inutile per farlo in.
monoceres

5
Haha, questo è brillante ... E 'sorprendente quanto la funzionalità si perde in questo modo, eppure quanta funzionalità si può tornare indietro facendo cose come int = (2).__class__, str = ''.__class__, True = (1 == 1)ecc ...
Chinmay Kanchi

@monoceres, come chiameresti quella copia e dove la nasconderesti in modo che non venga cancellata anche lei? -)
Alex Martelli

2
Più uso Python, più lo amo. Non solo è un ottimo linguaggio, puoi anche passare ore semplicemente giocherellando con esso e facendogli fare cose che davvero non dovresti ;-)
Chinmay Kanchi

1
Forse l'ho preso nel modo sbagliato, ma ho affrontato un problema: quando lo usi for n in dir(): ... if n[0]!='_': delattr(this, n)in un momento n=thise lo elimini nel ciclo! Quindi alla successiva iterazione ottieni Errore nel tentativo delattr(this,n)perché l'hai appena cancellato! :) Quindi non funziona correttamente
Mikhail_Sam

59

No, è meglio riavviare l'interprete

IPython è un eccellente sostituto dell'interprete in bundle e ha il %resetcomando che di solito funziona


1
Con "No" intendi che non dovrei farlo o che è impossibile? Se dici che non dovrei farlo potresti spiegare perché?
snakile

6
+1: Mi ci vuole meno di un quarto di secondo per ctrl-dpoi pyt-> tabtornare nell'interprete. Nessun motivo per fare qualcosa di speciale qui.
Sam Dolan

3
% reset funziona per la maggior parte delle variabili, per alcune no. Per me solo riavviare l'interprete garantisce la pulizia di tutto.
artemis_clyde

3
Usa %reset -fper essere non interattivo. stackoverflow.com/questions/38798181/…
Joachim Wagner

28

Se scrivi una funzione, una volta che la lasci tutti i nomi all'interno scompaiono.

Il concetto si chiama spazio dei nomi ed è così buono che è entrato nello Zen di Python :

Gli spazi dei nomi sono una grande idea clamorosa: facciamo di più di quelli!

Anche lo spazio dei nomi di IPython può essere ripristinato con il comando magico %reset -f. (Il -fsignifica "forza"; in altre parole, "non chiedermi se voglio veramente cancellare tutte le variabili, fallo e basta.")


1
Aggiungo l'ovvio: se metti tutto all'interno di una funzione principale (comprese le importazioni) ottieni in pratica un posto di lavoro che puoi resettare semplicemente uscendo da quella funzione. Credo che sia proprio a questo che era destinata la domanda.
David

8
from IPython import get_ipython;   
get_ipython().magic('reset -sf')

3
Dai un'occhiata a Come rispondere
Adonis

1
o semplicemente%reset -sf
Bal Krishna Jha

1
in realtà, il comando% reset -sf non funziona e genera un errore, quando esegui il tuo script python con il prompt di anaconda (anche se quando hai usato try- tranne; non funziona). Puoi provare lo stesso e vedrai. Ma l'uso della libreria ipython risolverà questo problema, in ogni caso possibile.
Anurag Gupta

5

Questa è una versione modificata della risposta di Alex. Possiamo salvare lo stato dello spazio dei nomi di un modulo e ripristinarlo utilizzando i seguenti 2 metodi ...

__saved_context__ = {}

def saveContext():
    import sys
    __saved_context__.update(sys.modules[__name__].__dict__)

def restoreContext():
    import sys
    names = sys.modules[__name__].__dict__.keys()
    for n in names:
        if n not in __saved_context__:
            del sys.modules[__name__].__dict__[n]

saveContext()

hello = 'hi there'
print hello             # prints "hi there" on stdout

restoreContext()

print hello             # throws an exception

Puoi anche aggiungere una riga "clear = restoreContext" prima di chiamare saveContext () e clear () funzionerà come clear di matlab.


1
Bella risposta! Credo che per Python 3 vorrai modificare RestoreContext con names = list(sys.modules[__name__].__dict__.keys()), altrimenti Python si lamenterà che hai cambiato la dimensione del dizionario mentre iterando attraverso il suo dict_keysoggetto.
Sam Bader

Inoltre, per chi vuole import questa risposta (cioè ho questo salvato e lo importa da un quaderno Jupyter per cancellare lo spazio dei nomi tra i diversi problemi in un compito a casa), penso che vorrai usare al "__main__"posto di __name__.
Sam Bader

3

In Spyder è possibile configurare la console IPython per ogni file Python per cancellare tutte le variabili prima di ogni esecuzione nel menu Run -> Configuration -> General settings -> Remove all variables before execution.


2

La globals()funzione restituisce un dizionario, dove le chiavi sono nomi di oggetti che puoi nominare (e i valori, tra l'altro, sono ids di questi oggetti). La exec()funzione prende una stringa e la esegue come se la digitassi in una console python. Quindi, il codice è

for i in list(globals().keys()):
    if(i[0] != '_'):
        exec('del {}'.format(i))

Sebbene questo snippet di codice possa risolvere la domanda, includere una spiegazione aiuta a migliorare la qualità della tua risposta. Ricorda che stai rispondendo alla domanda per i lettori in futuro e quelle persone potrebbero non conoscere i motivi del tuo suggerimento sul codice.
Stefan Crain

Grazie. Adesso va meglio?
Kolay.Ne


0

Non è il modo più semplice per creare una classe che continui tutte le variabili necessarie? Quindi hai un oggetto con tutte le variabili curretn e, se necessario, puoi sovrascrivere questa variabile?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.