Bagaimana mengimpor kelas yang ditentukan dalam __init__.py

105

Saya mencoba mengatur beberapa modul untuk saya gunakan sendiri. Saya punya sesuatu seperti ini:

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

Di lib/__init__.py, saya ingin mendefinisikan beberapa kelas yang akan digunakan jika saya mengimpor lib. Namun, saya tidak bisa memahaminya tanpa memisahkan kelas ke dalam file, dan mengimpornya __init__.py.

Daripada mengatakan:

    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

Saya ingin sesuatu seperti ini:

    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

Apakah mungkin, atau apakah saya harus memisahkan kelas ke file lain?

EDIT

Oke, jika saya mengimpor lib dari skrip lain, saya dapat mengakses kelas Helper. Bagaimana saya dapat mengakses kelas Helper dari settings.py?

Contoh di sini menjelaskan Referensi Intra-Paket. Saya mengutip "submodul sering kali perlu merujuk satu sama lain". Dalam kasus saya, lib.settings.py membutuhkan Helper dan lib.foo.someobject membutuhkan akses ke Helper, jadi di mana saya harus mendefinisikan kelas Helper?

scottm
sumber
Contoh terakhir Anda di sana harus berhasil. Apakah Anda melihat ImportError? Bisakah Anda menempelkan detailnya?
Joe Holloway

Jawaban:

81
  1. ' lib/'S direktori induk harus dalam sys.path.

  2. ' lib/__init__.py' Anda mungkin terlihat seperti ini:

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

Maka contoh berikut akan berfungsi:

from lib.settings import Values
from lib import Helper

Jawaban untuk versi pertanyaan yang sudah diedit:

__init__.pymenentukan tampilan paket Anda dari luar. Jika Anda perlu menggunakan Helperdi settings.pymaka tentukan Helperdi file yang berbeda misalnya, ' lib/helper.py'.

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

2 direktori, 6 file

Perintah:

$ python import_submodule.py

Keluaran:

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
jfs
sumber
Bagaimana saya bisa mengimpor kelas Helper di file settings.py di contoh saya?
scottm
Saya tidak mengerti mengapa itu melingkar. Jika settings.py membutuhkan Helper dan mengatakan foo.someobject.py membutuhkan Helper, di manakah Anda menyarankan saya mendefinisikannya?
scottm
wow, kata "helper" mulai kehilangan arti dalam contoh itu. Namun, Anda telah menunjukkan kepada saya apa yang saya cari.
scottm
3
suara positif untuk "__init__.py mendefinisikan bagaimana tampilan paket Anda dari luar."
Petri
19

Jika lib/__init__.pymendefinisikan kelas Helper maka di settings.py Anda dapat menggunakan:

from . import Helper

Ini berhasil karena. adalah direktori saat ini, dan bertindak sebagai sinonim untuk paket lib dari sudut pandang modul pengaturan. Perhatikan bahwa tidak perlu mengekspor Helper melalui __all__.

(Dikonfirmasi dengan python 2.7.10, berjalan di Windows.)

yoyo
sumber
1
Ini berfungsi dengan baik untuk saya, downvoters tolong jelaskan ketidaksenangan Anda?
yoyo
8

Anda hanya menempatkannya di __init__.py.

Jadi dengan test / class.py menjadi:

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

... dan uji / __ init__.py menjadi:

from classes import *

class Helper(object): pass

Anda dapat mengimpor tes dan memiliki akses ke A, B, dan Helper

>>> import test
>>> test.A
<class 'test.classes.A'>
>>> test.B
<class 'test.classes.B'>
>>> test.Helper
<class 'test.Helper'>
Aaron Maenpaa
sumber
Dari mana Anda melakukan impor?
Aaron Maenpaa
Katakanlah saya ingin mengimpor Helper dari lib / settings.py?
scottm
1
Itu hampir pasti akan menghasilkan impor melingkar (pengaturan akan mengimpor tes dan tes akan mengimpor pengaturan) ... yang akan menghasilkan NameError yang Anda gambarkan. Jika Anda menginginkan pembantu yang digunakan di dalam paket, Anda harus menentukan modul internal yang digunakan kode Anda.
Aaron Maenpaa
1
Pembantu di init .py harusnya untuk pengguna eksternal untuk menyederhanakan API Anda.
Aaron Maenpaa
1
Jika ini bukan bagian dari API, maka init .py bukanlah tempat untuk itu. lib / internal.py atau yang serupa akan jauh lebih baik (yang memiliki tujuan ganda mengurangi kemungkinan impor melingkar).
Aaron Maenpaa
5

Tambahkan sesuatu seperti ini ke lib/__init__.py

from .helperclass import Helper

sekarang Anda dapat mengimpornya secara langsung:

from lib import Helper

Dawid Gosławski
sumber
4

Sunting, karena saya salah paham dengan pertanyaan:

Masukkan saja Helperkelasnya __init__.py. Itu benar-benar pythonic. Rasanya aneh datang dari bahasa seperti Java.

Richard Levasseur
sumber
Kamu salah paham. Saya ingin menghilangkan file helperClass.py jika memungkinkan.
scottm
Richard bukan satu-satunya yang salah paham. Teladan Anda seharusnya berhasil. Apa traceback itu?
Troy J. Farrell
Nah, kemudian saya membaca dokumen dengan benar. Jadi, sekarang saya baru saja membuat test case dan berfungsi dengan baik.
scottm
Saya memiliki penyiapan yang sama dalam paket saya, tetapi saya mendapatkan ImportError "tidak dapat mengimpor nama Pembantu"
scottm
Saya rasa masalah saya adalah saya mencoba mengimpor kelas Helper dari settings.py, bagaimana saya bisa melakukannya?
scottm
2

Ya, itu mungkin. Anda mungkin juga ingin menentukan __all__dalam __init__.pyfile. Ini adalah daftar modul yang akan diimpor saat Anda melakukannya

from lib import *
vartec
sumber
-6

Mungkin ini bisa berhasil:

import __init__ as lib
Turion
sumber