Jak wyczyścić wszystkie zmienne w środku skryptu Pythona?

86

Szukam czegoś podobnego do 'wyczyść' w Matlabie: Polecenie / funkcja, która usuwa wszystkie zmienne z obszaru roboczego, zwalniając je z pamięci systemu. Czy jest coś takiego w Pythonie?

EDYCJA: Chcę napisać skrypt, który w pewnym momencie czyści wszystkie zmienne.

wąż
źródło
2
Będzie pomocne, jeśli zmienisz tytuł na coś w rodzaju „Jak wyczyścić wszystkie zmienne w środku skryptu Pythona?” do przyszłych poszukiwań na ten temat, bo „Jak zrestartować okno poleceń w Pythonie?” nie ma nic wspólnego z tym, o co tak naprawdę pytasz.
Sam Dolan
Czy możesz podać jakiś możliwy kontekst, w którym ma to sens?
S.Lott
2
Brzmi jak kolejny przypadek próby przeniesienia nawyków kodowania z ich rodzimego środowiska do takiego, w którym nie mają one żadnego sensu.
Glenn Maynard
Jeśli martwisz się tylko niektórymi masywnymi obiektami (obrazami lub innymi ogromnymi tablicami), możesz to zrobić del, gdy skończysz. Jeśli po prostu martwisz się, że przestrzeń nazw jest zagracona, prawdopodobnie powinieneś ponownie rozważyć swój projekt, używając tak wielu nazw. Na przykład w przypadku serii przekształceń obrazu zachowanie każdego pośredniego kroku jest prawdopodobnie niepotrzebne.
Nick T
3
@ S.Lott: eksploracyjna analiza naukowa w konsoli. Często pojawia się wiele niechcianych zmiennych (po wypróbowaniu różnych rzeczy, a następnie stwierdzeniu, że nie jest to odpowiednia ścieżka). Ale w tym przypadku odpowiedź Johna La Rooya jest najbardziej odpowiednia.
naught101

Odpowiedzi:

69

Poniższa sekwencja poleceń usuwa wszystkie nazwy z bieżącego modułu:

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

Wątpię, czy naprawdę chcesz to zrobić, ponieważ „każde imię” zawiera wszystkie wbudowane elementy, więc po takim całkowitym wymazaniu niewiele możesz zrobić. Pamiętaj, że w Pythonie tak naprawdę nie ma czegoś takiego jak „zmienna” - istnieją obiekty różnego rodzaju (w tym moduły, funkcje, klasy, liczby, łańcuchy znaków, ...) i są nazwy powiązane z obiektami; sekwencja usuwa każdą nazwę z modułu (odpowiednie obiekty znikają wtedy i tylko wtedy, gdy wszystkie odniesienia do nich zostały właśnie usunięte).

Może chcesz być bardziej selektywny, ale trudno odgadnąć, co masz na myśli, chyba że chcesz być bardziej szczegółowy. Ale żeby podać przykład:

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

Ta sekwencja pozostawia same nazwy, które są prywatne lub magiczne, w tym __builtins__nazwę specjalną, która zawiera wszystkie wbudowane nazwy. Tak więc wbudowane nadal działają - na przykład:

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

Jak widzisz, nazwa n(w tym zmienna kontrolna for) również się trzyma (ponieważ jest ponownie wiązana w forklauzuli za każdym razem), więc może lepiej nazwać tę zmienną kontrolną _, na przykład, aby wyraźnie pokazać special "(dodatkowo w interaktywnym interpretatorze nazwa i tak _jest ponownie wiązana po każdym pełnym wyrażeniu wprowadzonym w znaku zachęty, do wartości tego wyrażenia, więc nie będzie trwało długo ;-).

W każdym razie, kiedy już dokładnie określić, co to jest chcesz zrobić, to nie jest trudne do zdefiniowania funkcji do celów i umieścić go w pliku startowego (jeśli chcesz go tylko w sesjach interaktywnych) lub plik site-Dostosuj ( jeśli chcesz to w każdym skrypcie).

Alex Martelli
źródło
2
Cóż, zawsze możesz zachować kopię oryginalnego słownika podczas uruchamiania, a następnie usunąć dodane nazwy;) Jednak myślę, że jest to wyraźne nadużycie systemu dynamicznego i nie mogę wymyślić bezsensownej sytuacji, aby to zrobić in.
monoceres
5
Haha, to jest genialny ... To zaskakujące, jak wiele funkcjonalności tracisz w ten sposób, a jednak ile funkcjonalność można wrócić, wykonując takie rzeczy int = (2).__class__, str = ''.__class__, True = (1 == 1)etc ...
Chinmay Kanchi
@monoceres, jak nazwałbyś tę kopię i gdzie ją schowałbyś, żeby też nie została usunięta? -)
Alex Martelli
2
Im więcej używam Pythona, tym bardziej go kocham. Jest to nie tylko świetny język, ale możesz też spędzać godziny po prostu bawiąc się nim i zmuszając go do robienia rzeczy, których naprawdę nie powinieneś ;-)
Chinmay Kanchi
1
Może źle to zrozumiałem, ale napotkałem jeden problem: kiedy używasz for n in dir(): ... if n[0]!='_': delattr(this, n)w pewnym momencie n=thisi usuwasz go w pętli! Więc przy następnej iteracji delattr(this,n)pojawi się błąd Error probing, ponieważ właśnie go usunąłeś! :) Więc to nie działa poprawnie
Mikhail_Sam
60

Nie, najlepiej jest zrestartować tłumacza

IPython jest doskonałym zamiennikiem dołączonego interpretera i ma %resetpolecenie, które zwykle działa

John La Rooy
źródło
1
Mówiąc „nie”, masz na myśli, że nie powinienem tego robić, czy to niemożliwe? Jeśli powiesz, że nie powinienem tego robić, czy możesz wyjaśnić dlaczego?
snakile
6
+1: Potrzeba mi mniej niż ćwierć sekundy, ctrl-dzanim pyt-> tabwrócę do tłumacza. Nie ma powodu, żeby robić tu coś wymyślnego.
Sam Dolan
3
% reset działa dla większości zmiennych, dla niektórych nie. Dla mnie tylko ponowne uruchomienie tłumacza gwarantuje wyczyszczenie wszystkiego.
artemis_clyde
3
Użyj, %reset -faby nie być interaktywnym. stackoverflow.com/questions/38798181/…
Joachim Wagner
27

Jeśli napiszesz funkcję, po jej pozostawieniu wszystkie nazwy wewnątrz znikną.

Pojęcie to nazywa się przestrzenią nazw i jest tak dobre, że stało się zen Pythona :

Przestrzenie nazw to jeden wspaniały pomysł - zróbmy ich więcej!

Przestrzeń nazw IPythona można również zresetować za pomocą polecenia magic %reset -f. ( -fOznacza „wymuszenie”; innymi słowy: „nie pytaj mnie, czy naprawdę chcę usunąć wszystkie zmienne, po prostu zrób to”).

Jochen Ritzel
źródło
Dodam to, co oczywiste: jeśli umieścisz wszystko w głównej funkcji (w tym import), w praktyce otrzymasz miejsce pracy, które możesz zresetować, po prostu opuszczając tę ​​funkcję. Uważam, że właśnie o to chodziło w tym pytaniu.
David
8
from IPython import get_ipython;   
get_ipython().magic('reset -sf')
Anurag Gupta
źródło
3
Proszę spojrzeć na Jak odpowiedzieć
Adonis
1
lub po prostu%reset -sf
सत्यमेव जयते
1
w rzeczywistości polecenie% reset -sf nie działa i generuje błąd, gdy uruchamiasz skrypt Pythona z zachętą do polecenia anaconda (nawet jeśli użyłeś try- z wyjątkiem; to nie działa). Możesz spróbować tego samego, a zobaczysz. Jednak użycie biblioteki ipython rozwiąże ten problem w każdym możliwym przypadku.
Anurag Gupta
5

To jest zmodyfikowana wersja odpowiedzi Alexa. Możemy zapisać stan przestrzeni nazw modułu i przywrócić go za pomocą następujących 2 metod ...

__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

Możesz także dodać wiersz „clear = restoreContext” przed wywołaniem metody saveContext (), a funkcja clear () będzie działać jak metoda clear w programie Matlab.

Dzbanek
źródło
1
Świetna odpowiedź! Sądzę, że w przypadku Pythona 3 będziesz chciał zmodyfikować restoreContext names = list(sys.modules[__name__].__dict__.keys()), w przeciwnym razie Python będzie narzekał, że zmieniłeś rozmiar słownika podczas iteracji przez jego dict_keysobiekt.
Sam Bader
Również dla tych, którzy chcą importtej odpowiedzi (tj. Mam to zapisane i importuję to z notatnika Jupyter, aby wyczyścić przestrzeń nazw między różnymi problemami w zadaniu domowym), myślę, że będziesz chciał użyć "__main__"zamiast __name__.
Sam Bader
3

W Spyder można skonfigurować konsolę IPython dla każdego pliku Pythona, aby wyczyścić wszystkie zmienne przed każdym wykonaniem w Menu Run -> Configuration -> General settings -> Remove all variables before execution.

tardis
źródło
2

globals()Zwraca słownik, gdzie klucze są nazwami przedmiotów można Nazwisko (i wartości, nawiasem mówiąc, są ids tych obiektów) exec()funkcja przyjmuje ciąg i wykonuje go tak, jakby po prostu wpisz go w konsoli Pythona. Tak więc kod jest

for i in list(globals().keys()):
    if(i[0] != '_'):
        exec('del {}'.format(i))
Kolay.Ne
źródło
Chociaż ten fragment kodu może rozwiązać problem, dołączenie wyjaśnienia pomoże poprawić jakość Twojej odpowiedzi. Pamiętaj, że odpowiadasz na pytanie do czytelników w przyszłości, a osoby te mogą nie znać powodów, dla których zaproponowałeś kod.
Stefan Crain
Dziękuję Ci. Czy teraz jest lepiej?
Kolay.Ne
0

W bezczynnym IDE jest Shell / Restart Shell. Cntrl-F6 zrobi to.

Harold Henson
źródło
0

Czy nie jest najłatwiejszym sposobem na utworzenie klasy zawierającej wszystkie potrzebne zmienne? Zatem masz jeden obiekt ze wszystkimi zmiennymi curretn i jeśli potrzebujesz, możesz nadpisać tę zmienną?

Ivan
źródło