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?


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

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.)


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'>

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


4

Sunting, karena saya salah paham dengan pertanyaan:

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


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 *

-6

Mungkin ini bisa berhasil:

import __init__ as lib
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.