Як імпортувати класи, визначені в __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.