2013-06-21 15 views
7

Wszyscy słyszeliśmy, że używanie from module import * jest złym pomysłem. Czy istnieje jednak sposób na importowanie podzbioru z zakresu zawartości module przy użyciu symbolu wieloznacznego?Python: import podzbiorów wieloznacznych

Na przykład:

module.py:

MODULE_VAR1 = "hello" 
MODULE_VAR2 = "world" 
MODULE_VAR3 = "The" 
MODULE_VAR4 = "quick" 
MODULE_VAR5 = "brown" 
... 
MODULE_VAR10 = "lazy" 
MODULE_VAR11 = "dog!" 
MODULE_VAR12 = "Now" 
MODULE_VAR13 = "is" 
... 
MODULE_VAR98 = "Thats" 
MODULE_VAR99 = "all" 
MODULE_VAR100 = "folks!" 

def abs(): 
    print "Absolutely useful function: %s" % MODULE_VAR1 

Oczywiście nie chcemy używać from module import * ponieważ chcemy być nadrzędne funkcję abs. Załóżmy jednak, że chcemy, aby wszystkie zmienne MODULE_VAR* były dostępne lokalnie.

Po prostu wstawienie from module import MODULE_VAR* nie działa. Czy istnieje sposób, aby to osiągnąć?

Użyłem 100 zmiennych jako ilustrację, ponieważ wykonanie from module import MODULE_VAR1, MODULE_VAR2, MODULE_VAR3, ..., MODULE_VAR100 byłoby oczywiście niesamowicie nieporęczne i nie działałoby, gdyby dodano więcej zmiennych (np. MODULE_VAR101).

Odpowiedz

2

Można użyć zmiennej __all__, aby zaimportować określone zmienne podczas korzystania ze składni import *.

mymodule.py

__all__ = [ 
    'MODULE_VAR1', 
    'MODULE_VAR2', 
    'MODULE_VAR3', 
    'MODULE_VAR4', 
    'MODULE_VAR5', 
] 

MODULE_VAR1 = "hello" 
MODULE_VAR2 = "world" 
MODULE_VAR3 = "The" 
MODULE_VAR4 = "quick" 
MODULE_VAR5 = "brown" 

def abs(): 
    print "Absolutely useful function: %s" % MODULE_VAR1 

Wtedy możemy go używać wygląda następująco:

from mymodule import * 
print MODULE_VAR1 # hello 
print abs # <built-in function abs> 

Gdy moduł jest importowany za pomocą *, Python sprawdza moduł dla __all__ zmiennej, która może nadpisać co byłoby inaczej uznać normalne "publiczne" zmienne w module (które byłyby zmiennymi, które nie zaczynają się od podkreśleń) i pozwala jednoznacznie zdefiniować, które zmienne są "publiczne". Check out this question

+0

To jest świetne! Ale czy jest jakiś sposób osiągnięcia tego samego efektu, jeśli nie masz kontroli nad kodem źródłowym modułu? – seaotternerd

+0

Przepraszam, że źle zrozumiałem. Nie wiem w żaden sposób, aby natywnie importować określone zmienne z innego modułu. Ale jako bardzo proste rozwiązanie można utworzyć pomocnika, który importuje moduł i iteruje po atrybutach modułu, aby wyodrębnić pożądane zmienne. W twoim przykładzie uniemożliwiłoby to przesłonięcie zmiennej 'abs', ponieważ nie importujesz zmiennych modułu, ale sam moduł. Alternatywnie można * zaimportować * zmienne modułu w zakresie funkcji, uniemożliwiając zastąpienie wbudowanej funkcji 'abs'. Myślę, że @jsbueno ma doskonały przykład. – kuujo

+0

Nie wiem, czy źle zrozumiałeś - nie byłem osobą, która zadała pytanie, byłem po prostu ciekawy. Dzięki! – seaotternerd

7

Można mieć funkcję pomocnika za to - i można to zrobić bez magii:

import re 

def matching_import(pattern, module, globals): 
    for key, value in module.__dict__.items(): 
     if re.findall(pattern, key): 
      globals[key] = value 

Teraz można to zrobić na przykład:

from utils import matching_import 
import constants 

matching_import("MODULE_VAR.*", constants, globals()) 

Korzystanie globals() wyraźnie w ten sposób omija ramową introspekcję magiczną, która zwykle uważana jest za szkodliwą.

+0

Dobre rozwiązanie. +1 – kuujo