Python 3.2: „ Exception NameError: NameError("global name '__file__' is not defined",)”
sdaau
20
@ sdaau: __file__nie jest zdefiniowany w interaktywnym tłumaczu , ponieważ nie ma tam znaczenia. Jest on ustawiany przez implementację importu, więc jeśli użyjesz niestandardowego mechanizmu importu, może on również zostać rozbrojony.
Sven Marnach
8
Przynajmniej dla Pythona 2.7 uważam, że import osjest wymagany, aby to zadziałało. Dodałbym to do odpowiedzi.
Nick Chammas
14
@ cdunn2001: import osi import os.pathsą całkowicie równoważne.
Sven Marnach,
2
@ sven-marnach: Oh, masz rację . Robię to źle od lat!
cdunn2001
136
import sys
print sys.argv[0]
Spowoduje to wydrukowanie foo.pyna python foo.py, dir/foo.pyna python dir/foo.py, itd. Jest to pierwszy argument python. (Zauważ, że po py2exe będzie foo.exe.)
@DenisMalinovsky: zdefiniuj „nie będzie działać”. Jeśli zadzwonisz python linkfile.py, gdzie linkfile.pyjest dowiązanie symboliczne realfile.py, sys.argv[0]będzie 'linkfile.py', co może lub nie być tym, czego chcesz; z pewnością tego oczekuję . __file__jest to samo: będzie linkfile.py. Jeśli chcesz się dowiedzieć 'realfile.py'od 'linkfile.py'spróbować os.path.realpath('linkfile.py').
Chris Morgan
6
+1, ponieważ jest to (a) trochę starsze, a (b) nadal będzie działać w module (gdzie zmienną pliku byłby plik modułu, a nie wykonywany).
Robert
Ta odpowiedź jest miła, ponieważ działa również w IDLE. Uwaga: aby uzyskać tylko nazwę pliku, możesz napisać os.path.basename (sys.argv [0])
Steven Bluen
Co ważniejsze, to nie działa inaczej niż w głównym pliku. Nie używaj tego, użyj __file__zamiast tego.
Apollys popiera Monikę
CO!!! Próbowałeś nawet tego? Dokładnie odwrotnie. Pytający zapytał o nazwę działającego skryptu python - nie o plik, który jest aktualnie wykonywany. Wyobraź sobie, że masz skrypt, który w przypadku wystąpienia błędu drukuje nazwę skryptu wraz z dozwolonymi argumentami. Umieszczasz to w funkcji, używając jednej z tych 2 technik. W pewnym momencie zdecydujesz się przenieść funkcję do biblioteki zewnętrznej. Czy chcesz wydrukować nazwę uruchomionego skryptu głównego, czy nazwę uruchamianego pliku biblioteki?
John Deighan
70
Ze względu na kompletność, pomyślałem, że warto podsumować różne możliwe wyniki i podać odniesienia do dokładnego zachowania każdego z nich:
__file__jest ścieżką do pliku, z którego moduł został załadowany, jeśli został załadowany z pliku. W __file__przypadku niektórych typów modułów, takich jak moduły C , które są statycznie połączone z tłumaczem, może brakować atrybutu ; w przypadku modułów rozszerzeń ładowanych dynamicznie z biblioteki współdzielonej jest to ścieżka do pliku biblioteki współdzielonej.
Od Python3.4 roku, za numerze 18416 , __file__zawsze jest ścieżka bezwzględna, chyba że plik aktualnie wykonywany jest skrypt, który został wykonany bezpośrednio (nie przez tłumacza z -mopcji wiersza polecenia) przy użyciu ścieżki względnej.
__main__.__file__(wymaga importu __main__) po prostu uzyskuje dostęp do wyżej wymienionego __file__atrybutu modułu głównego , np. skryptu, który został wywołany z wiersza poleceń.
sys.argv[0](wymaga importu sys) to nazwa skryptu, która została wywołana z wiersza poleceń i może być ścieżką bezwzględną, jak opisano w oficjalnej dokumentacji :
argv[0]to nazwa skryptu (jest to zależne od systemu operacyjnego, czy jest to pełna nazwa ścieżki, czy nie). Jeśli polecenie zostało wykonane przy użyciu -copcji wiersza polecenia interpretera, argv[0]ustawia się na ciąg '-c'. Jeśli do interpretera języka Python nie przekazano żadnej nazwy skryptu, argv[0]oznacza to, że jest to pusty ciąg.
Jak wspomniano w innej odpowiedzi na to pytanie , skrypty Pythona, które zostały przekonwertowane na samodzielne programy wykonywalne za pomocą narzędzi takich jak py2exe lub PyInstaller, mogą nie wyświetlać pożądanego wyniku podczas korzystania z tego podejścia (tzn. Zawierająsys.argv[0] nazwę pliku wykonywalnego zamiast nazwy głównego pliku Pythona w tym pliku wykonywalnym).
Jeśli wydaje się, że żadna z wyżej wymienionych opcji nie działa, prawdopodobnie z powodu nieregularnej operacji importowania, moduł inspekcji może okazać się przydatny. W szczególności, powołując się inspect.getfile(...)na inspect.currentframe()może pracować, choć ten ostatni będzie powrócićNone , gdy uruchomiony w implementacji bez Pythona stos ramki.
Obsługa dowiązań symbolicznych
Jeśli bieżący skrypt jest dowiązaniem symbolicznym, wszystkie powyższe zwrócą ścieżkę dowiązania symbolicznego, a nie ścieżkę rzeczywistego pliku, i os.path.realpath(...)należy je wywołać w celu wyodrębnienia tego ostatniego.
Dalsze manipulacje, które wyodrębniają rzeczywistą nazwę pliku
os.path.basename(...)może być wywoływany na dowolnym z powyższych w celu wyodrębnienia rzeczywistej nazwy pliku i os.path.splitext(...)może być wywoływany na rzeczywistej nazwie pliku w celu obcięcia jego sufiksu, jak w os.path.splitext(os.path.basename(...)).
Zauważ, że __file__da plik, w którym znajduje się ten kod, który można importować i różni się od interpretowanego pliku głównego. Aby uzyskać główny plik, można użyć specjalnego modułu __main__ :
import __main__ as main
print(main.__file__)
Zauważ, że __main__.__file__działa w Pythonie 2.7, ale nie w 3.2, więc użyj składni import-as jak wyżej, aby była przenośna.
Działa to w wielu przypadkach, ale nie wtedy, gdy używam rPythonpakietu z Rjęzyka. To musi być wyjątkowy przypadek, który jest po prostu zbyt trudny do opanowania.
Leonid
Rzeczywiście, pakiet rPython zawiera interpreter Pythona, co oznacza, że nie ma „głównego” pliku, takiego jak w przypadku, gdy Python działa samodzielnie (to samo zachowanie występuje przy każdym osadzeniu Pythona). Importuje __main__wewnętrznie, do użycia w przekazywaniu zmiennych między Ri python, więc stosunkowo łatwo byłoby ustawić go __main__.__file__przed wywołaniem czegokolwiek innego, ale nie jestem nawet pewien, jaka byłaby odpowiednia wartość w tym przypadku.
Perkins
42
Powyższe odpowiedzi są dobre. Ale uznałem tę metodę za bardziej wydajną, korzystając z powyższych wyników.
Powoduje to, że rzeczywista nazwa pliku skryptu nie jest ścieżką.
import sys
import os
file_name = os.path.basename(sys.argv[0])
Lubię też rozdzielać rozszerzenie, więc używam: os.path.splitext (os.path.basename (sys.argv [0])) [0]
RufusVS
19
W przypadku nowoczesnych wersji Python (3.4+) Path(__file__).namepowinno być bardziej idiomatyczne. Ponadto, Path(__file__).stemdaje nazwę skryptu bez .pyrozszerzenia.
wszystkie te odpowiedzi są świetne, ale mają pewne problemy, których możesz nie zobaczyć na pierwszy rzut oka.
pozwala zdefiniować, co chcemy - chcemy nazwę skryptu, który został wykonany, a nie nazwę bieżącego modułu - więc __file__będzie działać tylko wtedy, gdy zostanie użyty w wykonanym skrypcie, a nie w zaimportowanym module.
sys.argvjest również wątpliwe - co jeśli twój program został wywołany przez pytest? czy pydoc runner? lub jeśli został nazwany przez uwsgi?
i - istnieje trzecia metoda uzyskania nazwy skryptu, której nie widziałem w odpowiedziach - Możesz sprawdzić stos.
Innym problemem jest to, że Ty (lub inny program) możesz manipulować sys.argvi __main__.__file__- może być obecny, może nie być. Może być poprawny lub nie. Przynajmniej możesz sprawdzić, czy skrypt (pożądany wynik) istnieje!
moja biblioteka bitranox / lib_programname w github robi dokładnie to:
sprawdź, czy __main__jest obecny
sprawdź, czy __main__.__file__jest obecny
daje __main__.__file__prawidłowy wynik (czy ten skrypt istnieje?)
jeśli nie: sprawdź sys.argv:
czy w sys.argv jest pytest, docrunner itp? -> jeśli tak, zignoruj to
czy możemy uzyskać prawidłowy wynik tutaj?
jeśli nie: sprawdź stos i uzyskaj stamtąd wynik
jeśli również stos nie daje poprawnego wyniku, należy zgłosić wyjątek.
tą drogą, moje rozwiązanie działa do tej pory setup.py test, uwsgi, pytest, pycharm pytest, pycharm docrunner (doctest), dreampie,eclipse
jest też miły artykuł na blogu o tym problemie autorstwa Dough Hellman, „Określanie nazwy procesu w Pythonie”
Exception NameError: NameError("global name '__file__' is not defined",)
”__file__
nie jest zdefiniowany w interaktywnym tłumaczu , ponieważ nie ma tam znaczenia. Jest on ustawiany przez implementację importu, więc jeśli użyjesz niestandardowego mechanizmu importu, może on również zostać rozbrojony.import os
jest wymagany, aby to zadziałało. Dodałbym to do odpowiedzi.import os
iimport os.path
są całkowicie równoważne.Spowoduje to wydrukowanie
foo.py
napython foo.py
,dir/foo.py
napython dir/foo.py
, itd. Jest to pierwszy argumentpython
. (Zauważ, że po py2exe będziefoo.exe
.)źródło
python linkfile.py
, gdzielinkfile.py
jest dowiązanie symbolicznerealfile.py
,sys.argv[0]
będzie'linkfile.py'
, co może lub nie być tym, czego chcesz; z pewnością tego oczekuję .__file__
jest to samo: będzielinkfile.py
. Jeśli chcesz się dowiedzieć'realfile.py'
od'linkfile.py'
spróbowaćos.path.realpath('linkfile.py')
.__file__
zamiast tego.Ze względu na kompletność, pomyślałem, że warto podsumować różne możliwe wyniki i podać odniesienia do dokładnego zachowania każdego z nich:
__file__
jest aktualnie wykonywanym plikiem, jak wyszczególniono w oficjalnej dokumentacji :Od Python3.4 roku, za numerze 18416 ,
__file__
zawsze jest ścieżka bezwzględna, chyba że plik aktualnie wykonywany jest skrypt, który został wykonany bezpośrednio (nie przez tłumacza z-m
opcji wiersza polecenia) przy użyciu ścieżki względnej.__main__.__file__
(wymaga importu__main__
) po prostu uzyskuje dostęp do wyżej wymienionego__file__
atrybutu modułu głównego , np. skryptu, który został wywołany z wiersza poleceń.sys.argv[0]
(wymaga importusys
) to nazwa skryptu, która została wywołana z wiersza poleceń i może być ścieżką bezwzględną, jak opisano w oficjalnej dokumentacji :Jak wspomniano w innej odpowiedzi na to pytanie , skrypty Pythona, które zostały przekonwertowane na samodzielne programy wykonywalne za pomocą narzędzi takich jak py2exe lub PyInstaller, mogą nie wyświetlać pożądanego wyniku podczas korzystania z tego podejścia (tzn. Zawierają
sys.argv[0]
nazwę pliku wykonywalnego zamiast nazwy głównego pliku Pythona w tym pliku wykonywalnym).Jeśli wydaje się, że żadna z wyżej wymienionych opcji nie działa, prawdopodobnie z powodu nieregularnej operacji importowania, moduł inspekcji może okazać się przydatny. W szczególności, powołując się
inspect.getfile(...)
nainspect.currentframe()
może pracować, choć ten ostatni będzie powrócićNone
, gdy uruchomiony w implementacji bez Pythona stos ramki.Obsługa dowiązań symbolicznych
Jeśli bieżący skrypt jest dowiązaniem symbolicznym, wszystkie powyższe zwrócą ścieżkę dowiązania symbolicznego, a nie ścieżkę rzeczywistego pliku, i
os.path.realpath(...)
należy je wywołać w celu wyodrębnienia tego ostatniego.Dalsze manipulacje, które wyodrębniają rzeczywistą nazwę pliku
os.path.basename(...)
może być wywoływany na dowolnym z powyższych w celu wyodrębnienia rzeczywistej nazwy pliku ios.path.splitext(...)
może być wywoływany na rzeczywistej nazwie pliku w celu obcięcia jego sufiksu, jak wos.path.splitext(os.path.basename(...))
.Od Pythona 3.4 roku, za PEP 428 The
PurePath
klasa zpathlib
modułu mogą być również stosowane na którekolwiek z powyższych. W szczególnościpathlib.PurePath(...).name
wyodrębnia rzeczywistą nazwę pliku ipathlib.PurePath(...).stem
wyodrębnia rzeczywistą nazwę pliku bez przyrostka.źródło
Zauważ, że
__file__
da plik, w którym znajduje się ten kod, który można importować i różni się od interpretowanego pliku głównego. Aby uzyskać główny plik, można użyć specjalnego modułu __main__ :Zauważ, że
__main__.__file__
działa w Pythonie 2.7, ale nie w 3.2, więc użyj składni import-as jak wyżej, aby była przenośna.źródło
rPython
pakietu zR
języka. To musi być wyjątkowy przypadek, który jest po prostu zbyt trudny do opanowania.__main__
wewnętrznie, do użycia w przekazywaniu zmiennych międzyR
ipython
, więc stosunkowo łatwo byłoby ustawić go__main__.__file__
przed wywołaniem czegokolwiek innego, ale nie jestem nawet pewien, jaka byłaby odpowiednia wartość w tym przypadku.Powyższe odpowiedzi są dobre. Ale uznałem tę metodę za bardziej wydajną, korzystając z powyższych wyników.
Powoduje to, że rzeczywista nazwa pliku skryptu nie jest ścieżką.
źródło
W przypadku nowoczesnych wersji Python (3.4+)
Path(__file__).name
powinno być bardziej idiomatyczne. Ponadto,Path(__file__).stem
daje nazwę skryptu bez.py
rozszerzenia.źródło
from pathlib import Path
pierwszy.pathlib
zostało wprowadzone w Pythonie 3.4, więc powinno działać od Pythona 3.4.Spróbuj tego:
źródło
Uwaga: Jeśli używasz Python 3+, powinieneś zamiast tego użyć funkcji print ()
Zakładając, że nazwa pliku to
foo.py
poniższy fragment kodulub
Podobnie jak w przypadku innych rozszerzeń z większą liczbą znaków, na przykład nazwa pliku
foo.pypy
Jeśli chcesz wyodrębnić z bezwzględnej ścieżki
wyjdzie
foo
źródło
__file__
isys.argv[0]
, patrz stackoverflow.com/questions/5851588/...Pierwszym argumentem w sys będzie nazwa bieżącego pliku, więc to zadziała
źródło
Jeśli wykonujesz nietypowy import (np. Jest to plik opcji), spróbuj:
Zauważ, że to zwróci bezwzględną ścieżkę do pliku.
źródło
możemy spróbować uzyskać bieżącą nazwę skryptu bez rozszerzenia.
źródło
Ponieważ OP poprosił o nazwę bieżącego pliku skryptu, wolałbym
źródło
Moje szybkie, brudne rozwiązanie:
źródło
os.path
do dzielenia nazw plikówos.path.abspath(__file__)
da ci absolutną ścieżkę (równieżrelpath()
dostępną).sys.argv[-1]
da ci względną ścieżkę.źródło
wszystkie te odpowiedzi są świetne, ale mają pewne problemy, których możesz nie zobaczyć na pierwszy rzut oka.
pozwala zdefiniować, co chcemy - chcemy nazwę skryptu, który został wykonany, a nie nazwę bieżącego modułu - więc
__file__
będzie działać tylko wtedy, gdy zostanie użyty w wykonanym skrypcie, a nie w zaimportowanym module.sys.argv
jest również wątpliwe - co jeśli twój program został wywołany przez pytest? czy pydoc runner? lub jeśli został nazwany przez uwsgi?i - istnieje trzecia metoda uzyskania nazwy skryptu, której nie widziałem w odpowiedziach - Możesz sprawdzić stos.
Innym problemem jest to, że Ty (lub inny program) możesz manipulować
sys.argv
i__main__.__file__
- może być obecny, może nie być. Może być poprawny lub nie. Przynajmniej możesz sprawdzić, czy skrypt (pożądany wynik) istnieje!moja biblioteka bitranox / lib_programname w github robi dokładnie to:
__main__
jest obecny__main__.__file__
jest obecny__main__.__file__
prawidłowy wynik (czy ten skrypt istnieje?)tą drogą, moje rozwiązanie działa do tej pory
setup.py test
,uwsgi
,pytest
,pycharm pytest
,pycharm docrunner (doctest)
,dreampie
,eclipse
jest też miły artykuł na blogu o tym problemie autorstwa Dough Hellman, „Określanie nazwy procesu w Pythonie”
źródło
Od wersji Python 3.5 możesz po prostu:
Zobacz więcej tutaj: https://docs.python.org/3.5/library/pathlib.html#pathlib.PurePath.stem
Na przykład mam plik w katalogu użytkownika o nazwie
test.py
z tym wewnątrz:uruchamianie tych wyjść:
źródło