Jak importować klasy zdefiniowane w __init__.py


105

Próbuję zorganizować niektóre moduły na własny użytek. Mam coś takiego:

lib/
  __init__.py
  settings.py
  foo/
    __init__.py
    someobject.py
  bar/
    __init__.py
    somethingelse.py

W programie lib/__init__.pychcę zdefiniować klasy, które będą używane podczas importowania lib. Jednak wydaje mi się, że nie mogę tego rozgryźć bez rozdzielenia klas na pliki i zaimportowania ich do formatu __init__.py.

Zamiast mówić:

    lib/
      __init__.py
      settings.py
      helperclass.py
      foo/
        __init__.py
        someobject.py
      bar/
        __init__.py
        somethingelse.py

from lib.settings import Values
from lib.helperclass import Helper

Chcę coś takiego:

    lib/
      __init__.py  #Helper defined in this file
      settings.py
      foo/
        __init__.py
        someobject.py
      bar/
        __init__.py
        somethingelse.py

from lib.settings import Values
from lib import Helper

Czy to możliwe, czy muszę rozdzielić klasę na inny plik?

EDYTOWAĆ

OK, jeśli zaimportuję lib z innego skryptu, mogę uzyskać dostęp do klasy pomocnika. Jak mogę uzyskać dostęp do klasy pomocnika z settings.py?

Przykładem tutaj opisuje Referencje wewnątrz opakowania. Cytuję „podmoduły często muszą odnosić się do siebie”. W moim przypadku lib.settings.py potrzebuje Helpera, a lib.foo.someobject potrzebuje dostępu do Helpera, więc gdzie powinienem zdefiniować klasę Helper?


Twój ostatni przykład powinien działać. Czy widzisz błąd ImportError? Czy możesz wkleić szczegóły?
— Joe Holloway

Odpowiedzi:


81
  1. lib/Katalog nadrzędny ' ' musi znajdować się w sys.path.

  2. Twój „ lib/__init__.py” może wyglądać tak:

    from . import settings # or just 'import settings' on old Python versions
    class Helper(object):
          pass

Wtedy następujący przykład powinien zadziałać:

from lib.settings import Values
from lib import Helper

Odpowiedź na zredagowaną wersję pytania:

__init__.pyokreśla, jak Twój pakiet wygląda z zewnątrz. Jeśli chcesz użyć Helperw, settings.pyzdefiniuj Helperw innym pliku, np. „ lib/helper.py”.

.
| `- import_submodule.py
    `- lib
    | - __init__.py
    | - foo
    | | - __init__.py
    | `- someobject.py
    | - helper.py
    `- settings.py

2 katalogi, 6 plików

Komenda:

$ python import_submodule.py

Wynik:

settings
helper
Helper in lib.settings
someobject
Helper in lib.foo.someobject

# ./import_submodule.py
import fnmatch, os
from lib.settings import Values
from lib import Helper

print
for root, dirs, files in os.walk('.'):
    for f in fnmatch.filter(files, '*.py'):
        print "# %s/%s" % (os.path.basename(root), f)
        print open(os.path.join(root, f)).read()
        print


# lib/helper.py
print 'helper'
class Helper(object):
    def __init__(self, module_name):
        print "Helper in", module_name


# lib/settings.py
print "settings"
import helper

class Values(object):
    pass

helper.Helper(__name__)


# lib/__init__.py
#from __future__ import absolute_import
import settings, foo.someobject, helper

Helper = helper.Helper


# foo/someobject.py
print "someobject"
from .. import helper

helper.Helper(__name__)


# foo/__init__.py
import someobject

Jak mogę zaimportować klasę Helper w pliku settings.py w moim przykładzie?
— scottm

Nie rozumiem, dlaczego jest to okólnik. Jeśli settings.py potrzebuje pomocnika i mówi, że foo.someobject.py potrzebuje pomocnika, gdzie sugerujesz, żebym to zdefiniował?
— scottm

wow, słowo „pomocnik” naprawdę zaczyna tracić znaczenie w tym przykładzie. Jednak pokazałeś mi, czego szukałem.
— scottm

3
upvoted dla "__init__.py określa, jak twój pakiet wygląda z zewnątrz."
— Petri

19

Jeśli lib/__init__.pydefiniuje klasę Helper, to w settings.py możesz użyć:

from . import Helper

To działa, ponieważ. jest katalogiem bieżącym i działa jako synonim pakietu lib z punktu widzenia modułu ustawień. Zauważ, że nie jest konieczne eksportowanie Helpera przez __all__.

(Potwierdzone w Pythonie 2.7.10, działającym w systemie Windows).


1
To działa dobrze dla mnie, downvoters proszę wyjaśnić swoje niezadowolenie?
— jojo

8

Po prostu umieściłeś je w __init__.py.

A więc z test / classes.py:

class A(object): pass
class B(object): pass

... i test / __ init__.py:

from classes import *

class Helper(object): pass

Możesz importować test i mieć dostęp do A, B i pomocnika

>>> import test
>>> test.A
<class 'test.classes.A'>
>>> test.B
<class 'test.classes.B'>
>>> test.Helper
<class 'test.Helper'>

Skąd robisz import?
— Aaron Maenpaa

Powiedz, że chcę zaimportować pomocnika z lib / settings.py?
— scottm

1
To prawie na pewno spowoduje cykliczny import (ustawienia zaimportują test, a test zaimportuje ustawienia) ... co spowoduje wygenerowanie opisanego przez Ciebie NameError. Jeśli potrzebujesz pomocników, które są używane wewnątrz pakietu, powinieneś zdefiniować wewnętrzny moduł, którego używa twój kod.
— Aaron Maenpaa

1
Pomocnicy w init .py powinni być przeznaczone dla użytkowników zewnętrznych, aby uprościć interfejs API.
— Aaron Maenpaa

1
Jeśli nie jest częścią API, to init .py naprawdę nie jest dla niego odpowiednim miejscem. lib / internal.py lub podobny byłby znacznie lepszy (co ma podwójny cel - zmniejszenie prawdopodobieństwa importu cyklicznego).
— Aaron Maenpaa

5

Dodaj coś takiego do lib/__init__.py

from .helperclass import Helper

teraz możesz go zaimportować bezpośrednio:

from lib import Helper


4

Edytuj, ponieważ źle zrozumiałem pytanie:

Po prostu włóż Helperklasę __init__.py. To całkowicie pytoniczne. Po prostu wydaje się dziwne z języków takich jak Java.


Nie zrozumiałeś. Jeśli to możliwe, chcę wyeliminować plik helperClass.py.
— scottm

Richard nie jest jedynym, który źle zrozumiał. Twój przykład powinien działać. Co to jest śledzenie?
— Troy J. Farrell

Cóż, w takim razie poprawnie przeczytałem dokumenty. Więc teraz właśnie zrobiłem przypadek testowy i działa dobrze.
— scottm

Mam taką samą konfigurację w moim pakiecie, ale jestem coraz ImportError „nie może nazwa import Helper”
— scottm

Myślę, że moim problemem jest to, że próbuję zaimportować klasę pomocnika z settings.py, jak mogę to zrobić?
— scottm

2

Tak to mozliwe. Możesz także chcieć zdefiniować __all__w __init__.pyplikach. Jest to lista modułów, które zostaną zaimportowane, gdy to zrobisz

from lib import *

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.