2012-07-28 13 views
11

W niektórych moich aplikacjach Django używam pliku settings_local.py, aby nadpisać ustawienia, które różnią się w różnych środowiskach (np. Programowanie, testowanie i produkcja). Ja pierwotnie używany następujący kod do włączenia jej zawartość w settings.py:Python: 'import *' vs execfile

try: 
    from settings_local import * 
except ImportError: 
    sys.stderr.write("The settings_local.py file is missing.\n") 
    DEBUG=False 

Niedawno znaleziono funkcję execfile i włączony do czegoś podobnego:

try: 
    execfile(path.join(PROJECT_ROOT, "settings_local.py")) 
except IOError: 
    sys.stderr.write("The settings_local.py file is missing.\n" 
    DEBUG=False 

zarówno do pracy zgodnie z przeznaczeniem, ale I” Jestem ciekawy, czy brakuje mi gotchów, i ogólnie, które podejście jest bardziej zalecane i dlaczego.

Odpowiedz

14

Używanie funkcji execfile spowoduje ocenę pliku źródłowego Pythona (.py) za każdym razem, gdy oceniany jest plik ustawień. Za każdym razem uruchamiasz parser Pythona. Używanie import niekoniecznie musi to robić (może używać pliku .pyc). Zwykle przy pierwszym uruchomieniu projektu w Pythonie (przynajmniej cPython) jest on kompilowany do kodu bajtowego i nie jest ponownie rekompilowany. Łamiesz to. To niekoniecznie jest problem, ale powinieneś być tego świadomy.

Użycie numeru spowoduje również, że wszystkie importowane pliki w pliku settings_local.py zostaną ponownie ocenione w zakresie modułu pliku settings.py. Zastosowanie import * zawierałoby wszystkie elementy w zakresie modułu settings_local.py. Efekt netto jest taki sam (wszystkie elementy zawarte w zakresie modułu settings_local.py są zawarte w settings.py), ale metoda jest inna.

Wreszcie, normalne jest, że moduły mają być wykonywane jako moduły, a nie dołączone. Jest uzasadnione, aby kod zawierał takie elementy, jak os.path.dirname(__file__). Jeśli któryś z kodów użyłby tego, pomyliłbyś go, ponieważ kod nie byłby już uruchamiany w module, którego autor mógł rozsądnie oczekiwać.

Z mojego doświadczenia wynika, że ​​ludzie używają import, a nie execfile. Django to bardzo "konwencja dotycząca konfiguracji". Postępuj zgodnie z konwencją.

+5

'__file__' można łatwo podać za pomocą argumentów. Główna różnica polega na tym, że moduł jest importowany dokładnie raz, bez względu na to ile razy 'moduł importujący' jest wykonywany (' exec' wykonuje plik za każdym razem, gdy jest wywoływany), a 'import' nie wymaga jawnej ścieżki do pliku (więc działałoby również w archiwum zip). – jfs

+0

@ J.F.Sebastian To powinno być odpowiedzią. – Marcin

+3

Jedną z zalet, którą znalazłem na temat execfile (w przeciwieństwie do importu) jest to, że mogę to robić dynamicznie. W szczególności, jeśli mam listę modułów ustawień, mogę wykonać pętlę na liście, wywołując execfile na każdym z nich. Czy istnieje sposób na zrobienie tego za pomocą importu? –

2

Pierwsza wersja (from settings_local import *) jest tym, czego wszyscy mogli się spodziewać. Pozwoli to również analizatorom kodu znaleźć moduł.

8

Kolejna różnica: execfile otrzymuje słownik kontekstowy; kontekst globalny domyślnie lub określony słownik. Mogłoby to pozwolić jakieś dziwne rzeczy

dont_do_this.py:

# Probably not a good thing to do 
z=x+1 # an expression that involves an un-defined field 

Oczywiście

from dont_do_this import * 

zawiedzie.

Jednak

d={'x':1} 
execfile('dont_do_this.py', d) 

jest OK, a wyniki w d=={'x':1, 'z':2}

Zauważ, że

x=1 
execfile('dont_do_this.py') 

jest ok, a wyniki w zmiennej z dodawanych do globalnych.