Як імпортувати класи, визначені в __init__.py


105

Я намагаюся організувати деякі модулі для власного використання. У мене є щось подібне:

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

В lib/__init__.py, я хочу визначити деякі класи, які будуть використовуватись, якщо я імпортую lib. Однак я не можу зрозуміти це, не розділяючи класи на файли та імпортуючи їх __init__.py.

Замість того, щоб сказати:

    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

Я хочу щось подібне:

    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

Чи це можливо, або я повинен розділити клас на інший файл?

EDIT

Гаразд, якщо я імпортую lib з іншого сценарію, я можу отримати доступ до класу Helper. Як я можу отримати доступ до класу Helper з settings.py?

Приклад тут описує Посилання всередині пакету. Цитую "підмодулі часто потрібно посилатися один на одного". У моєму випадку lib.settings.py потребує Helper, а lib.foo.someobject потрібен доступ до Helper, тож де я повинен визначити клас Helper?


Ваш останній приклад там повинен працювати. Ви бачите ImportError? Чи можете ви вставити деталі?
Джо Холлоуей

Відповіді:


81
  1. ' lib/батьківський каталог повинен бути в sys.path.

  2. Ваш ' lib/__init__.py' може виглядати так:

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

Тоді повинен працювати наступний приклад:

from lib.settings import Values
from lib import Helper

Відповідь на відредаговану версію питання:

__init__.pyвизначає, як виглядає ваш пакет зовні. Якщо вам потрібно використовувати Helperв, settings.pyтоді визначте Helperв іншому файлі, наприклад, 'lib/helper.py ».

.
| `- import_submodule.py
    `- lib
    | - __init__.py
    | - фу
    | | - __init__.py
    | `- someobject.py
    | - helper.py
    `- settings.py

2 каталоги, 6 файлів

Команда:

$ python import_submodule.py

Вихід:

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

Як я можу імпортувати клас Helper у файл settings.py у своєму прикладі?
scottm

Я не розумію, чому це кругло. Якщо налаштування.py потребує Helper і скаже, що foo.someobject.py потрібен Helper, де ви пропонуєте мені це визначити?
scottm

Нічого, слово "помічник" дійсно починає втрачати значення в цьому прикладі. Однак ти показав мені, що я шукав.
scottm

3
аватар для "__init__.py визначає, як виглядає ваш пакет зовні".
Петрі

19

Якщо lib/__init__.pyвизначається клас Helper, то в settings.py ви можете використовувати:

from . import Helper

Це працює, тому що. є поточним каталогом і виступає синонімом пакету lib з точки зору модуля налаштувань. Зауважте, що не потрібно експортувати Helper через __all__.

(Підтверджено з python 2.7.10, працює на Windows.)


1
Це добре для мене, downvoters, будь ласка, поясніть ваше незадоволення?
yoyo

8

Ви просто помістіть їх у __init__.py.

Отже, якщо тест / class.py:

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

... і тест / __ init__.py:

from classes import *

class Helper(object): pass

Ви можете імпортувати тест і мати доступ до A, B та Helper

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

Звідки ви робите імпорт?
Аарон Маенпаа

Скажіть, я хочу імпортувати Helper з lib / settings.py?
scottm

1
Це майже напевно призведе до кругового імпорту (налаштування будуть імпортувати тест, а тест буде імпортувати налаштування) ... що призведе до описаного вами NameError. Якщо ви хочете, щоб помічники, які використовуються всередині пакета, вам слід визначити внутрішній модуль, який використовує ваш код.
Аарон Маенпаа

1
Помічники в init .py повинні бути зовнішніми користувачами для спрощення вашого API.
Аарон Маенпаа

1
Якщо він не є частиною API, то init .py дійсно не місце для нього. lib / Internal.py або подібне було б набагато кращим (що має подвійну мету - зменшити ймовірність кругового імпорту).
Аарон Маенпаа

5

Додайте щось подібне до lib/__init__.py

from .helperclass import Helper

тепер ви можете імпортувати його безпосередньо:

from lib import Helper


4

Відредагуйте, оскільки я неправильно зрозумів питання:

Просто кладіть Helperклас __init__.py. Це ідеально пітонічно. Це просто дивно, що йде з таких мов, як Java.


Ви неправильно зрозуміли. Я хочу усунути файл helperClass.py, якщо це можливо.
scottm

Річард не єдиний, хто неправильно зрозумів. Ваш приклад повинен працювати. Що таке трекбек?
Трой Дж. Фаррелл

Ну, тоді я правильно прочитав документи. Отже, зараз я просто зробив тестовий випадок, і він працює чудово.
scottm

У мене такий же параметр у моєму пакеті, але я отримую ImportError "не можу імпортувати ім'я помічника"
scottm

Я думаю, що моя проблема полягає в тому, що я намагаюся імпортувати клас Helper з settings.py, як я можу це зробити?
scottm

2

Так, можливо. Ви також можете визначити __all__у __init__.pyфайлах. Це список модулів, які будуть імпортовані, коли ви це зробите

from lib import *

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.