Saya ingin mewarisi dari kelas dalam file yang terletak di direktori di atas yang sekarang.
Apakah mungkin untuk mengimpor file itu secara relatif?
Saya ingin mewarisi dari kelas dalam file yang terletak di direktori di atas yang sekarang.
Apakah mungkin untuk mengimpor file itu secara relatif?
Jawaban:
from ..subpkg2 import mod
Per dokumen Python: Saat berada di dalam hierarki paket, gunakan dua titik, seperti yang dikatakan oleh dokumen pernyataan impor :
Saat menentukan modul apa yang akan diimpor, Anda tidak perlu menentukan nama absolut modul. Ketika modul atau paket terkandung dalam paket lain, dimungkinkan untuk melakukan impor relatif dalam paket teratas yang sama tanpa harus menyebutkan nama paket. Dengan menggunakan titik utama dalam modul atau paket yang ditentukan setelah
from
Anda dapat menentukan seberapa tinggi untuk melintasi hierarki paket saat ini tanpa menentukan nama yang tepat. Satu titik terkemuka berarti paket saat ini di mana modul membuat impor ada. Dua titik berarti naik satu tingkat paket . Tiga titik naik dua tingkat, dll. Jadi jika Anda mengeksekusifrom . import mod
dari modul dalampkg
paket maka Anda akan berakhir mengimporpkg.mod
. Jika Anda mengeksekusi . Spesifikasi untuk impor relatif terdapat di dalamnyafrom ..subpkg2 import mod
dari dalam,pkg.subpkg1
Anda akan mengimporpkg.subpkg2.mod
PEP 328 .
PEP 328 berkaitan dengan impor absolut / relatif.
import sys
sys.path.append("..") # Adds higher directory to python modules path.
Jawaban @ gimel benar jika Anda dapat menjamin hierarki paket yang ia sebutkan. Jika Anda tidak bisa - jika kebutuhan nyata Anda adalah seperti yang Anda ungkapkan, secara eksklusif terkait dengan direktori dan tanpa hubungan yang perlu dengan pengemasan - maka Anda perlu bekerja __file__
untuk mengetahui direktori induk (beberapa os.path.dirname
panggilan akan dilakukan; -), maka (jika direktori yang tidak sudah di sys.path
) tambahkan sementara insert mengatakan dir di bagian paling mulai dari sys.path
, __import__
, menghapus kata dir lagi - pekerjaan berantakan memang, tapi, "ketika Anda harus, Anda harus" (dan kemudian berusaha Pyhon untuk jangan pernah menghentikan programmer dari melakukan apa yang harus dilakukan - seperti standar ISO C mengatakan di bagian "Spirit of C" di kata pengantar! -).
Berikut ini contoh yang mungkin cocok untuk Anda:
import sys
import os.path
sys.path.append(
os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir)))
import module_in_parent_dir
sys.path
sehingga membuat modul yang sama tersedia dengan nama yang berbeda dan semua bug yang sesuai. autopath.py di pypy atau _preamble.py di twisted menyelesaikannya dengan menggunakan kriteria pencarian yang mengidentifikasi paket tingkat atas sambil melintasi direktori ke atas.
sys.path.remove(pathYouJustAdded)
setelah impor yang Anda butuhkan agar tidak mempertahankan jalur baru ini.
Impor modul dari direktori yang persis satu tingkat di atas direktori saat ini:
from .. import module
from .. import module
saya mendapat error ValueError: Mencoba impor relatif dalam non-paket dengan mengikuti rekomendasi
kata pengantar: Saya melakukan penulisan ulang substansial dari jawaban sebelumnya dengan harapan membantu memudahkan orang ke dalam ekosistem python, dan mudah-mudahan memberi setiap orang perubahan sukses terbaik dengan sistem impor python.
Ini akan mencakup impor relatif dalam satu paket , yang menurut saya merupakan kasus yang paling memungkinkan untuk pertanyaan OP.
Inilah sebabnya kami menulis import foo
untuk memuat modul "foo" dari root namespace, alih-alih menulis:
foo = dict(); # please avoid doing this
with open(os.path.join(os.path.dirname(__file__), '../foo.py') as foo_fh: # please avoid doing this
exec(compile(foo_fh.read(), 'foo.py', 'exec'), foo) # please avoid doing this
Inilah sebabnya mengapa kita dapat menanamkan python di lingkungan di mana tidak ada sistem file defacto tanpa menyediakan yang virtual, seperti Jython.
Karena dipisahkan dari sistem file memungkinkan impor menjadi fleksibel, desain ini memungkinkan untuk hal-hal seperti impor dari arsip / file zip, impor singleton, caching bytecode, ekstensi cffi, bahkan pemuatan definisi kode jarak jauh.
Jadi jika impor tidak digabungkan ke sistem file, apa artinya "satu direktori"? Kita harus memilih beberapa heuristik tetapi kita bisa melakukan itu, misalnya ketika bekerja di dalam suatu paket , beberapa heuristik telah didefinisikan yang membuat impor relatif suka .foo
dan..foo
bekerja dalam paket yang sama. Keren!
Jika Anda sungguh-sungguh ingin memasangkan pola pemuatan kode sumber Anda ke sistem file, Anda dapat melakukannya. Anda harus memilih heuristik Anda sendiri, dan menggunakan beberapa jenis mesin impor, saya sarankan importlib
Contoh importlib Python terlihat seperti ini:
import importlib.util
import sys
# For illustrative purposes.
file_path = os.path.join(os.path.dirname(__file__), '../foo.py')
module_name = 'foo'
foo_spec = importlib.util.spec_from_file_location(module_name, file_path)
# foo_spec is a ModuleSpec specifying a SourceFileLoader
foo_module = importlib.util.module_from_spec(foo_spec)
sys.modules[module_name] = foo_module
foo_spec.loader.exec_module(foo_module)
foo = sys.modules[module_name]
# foo is the sys.modules['foo'] singleton
Ada contoh proyek bagus yang tersedia secara resmi di sini: https://github.com/pypa/sampleproject
Paket python adalah kumpulan informasi tentang kode sumber Anda, yang dapat memberi tahu alat lain cara menyalin kode sumber Anda ke komputer lain, dan cara mengintegrasikan kode sumber Anda ke jalur sistem itu sehingga import foo
bekerja untuk komputer lain (terlepas dari penerjemah, sistem operasi host, dll)
Mari kita memiliki nama paket foo
, di beberapa direktori (lebih disukai direktori kosong).
some_directory/
foo.py # `if __name__ == "__main__":` lives here
Preferensi saya adalah membuat setup.py
sebagai saudara foo.py
, karena membuat menulis file setup.py lebih sederhana, namun Anda dapat menulis konfigurasi untuk mengubah / mengarahkan ulang semua yang dilakukan setuptools secara default jika Anda mau; misalnya meletakkan di foo.py
bawah direktori "src /" agak populer, tidak dibahas di sini.
some_directory/
foo.py
setup.py
.
#!/usr/bin/env python3
# setup.py
import setuptools
setuptools.setup(
name="foo",
...
py_modules=['foo'],
)
.
python3 -m pip install --editable ./ # or path/to/some_directory/
"dapat diedit" alias -e
akan mengarahkan kembali mesin pengimpor untuk memuat file sumber dalam direktori ini, alih-alih menyalin file yang sekarang aktif ke pustaka lingkungan pemasangan. Ini juga dapat menyebabkan perbedaan perilaku pada mesin pengembang, pastikan untuk menguji kode Anda! Ada alat selain pip, namun saya akan merekomendasikan pip menjadi pengantar :)
Saya juga suka membuat foo
"paket" (direktori berisi __init__.py
) alih-alih modul (file ".py" tunggal), baik "paket" dan "modul" dapat dimuat ke root namespace, modul memungkinkan ruang nama bersarang, yang sangat membantu jika kita ingin mengimpor "relatif satu direktori".
some_directory/
foo/
__init__.py
setup.py
.
#!/usr/bin/env python3
# setup.py
import setuptools
setuptools.setup(
name="foo",
...
packages=['foo'],
)
Saya juga suka membuat foo/__main__.py
, ini memungkinkan python untuk mengeksekusi paket sebagai modul, mis. python3 -m foo
Akan dieksekusi foo/__main__.py
sebagai __main__
.
some_directory/
foo/
__init__.py
__main__.py # `if __name__ == "__main__":` lives here, `def main():` too!
setup.py
.
#!/usr/bin/env python3
# setup.py
import setuptools
setuptools.setup(
name="foo",
...
packages=['foo'],
...
entry_points={
'console_scripts': [
# "foo" will be added to the installing-environment's text mode shell, eg `bash -c foo`
'foo=foo.__main__:main',
]
},
)
Mari kita selesaikan ini dengan beberapa modul lagi: Pada dasarnya, Anda dapat memiliki struktur direktori seperti ini:
some_directory/
bar.py # `import bar`
foo/
__init__.py # `import foo`
__main__.py
baz.py # `import foo.baz
spam/
__init__.py # `import foo.spam`
eggs.py # `import foo.spam.eggs`
setup.py
setup.py
secara konvensional menyimpan informasi metadata tentang kode sumber di dalamnya, seperti:
foo
, meskipun mengganti garis bawah untuk tanda hubung sangat populerpython ./setup.py test
Sangat ekspansif, bahkan dapat mengkompilasi ekstensi c on the fly jika modul sumber sedang diinstal pada mesin pengembangan. Untuk contoh setiap hari, saya sarankan setup.py PYPA Sample Repository
Jika Anda merilis artefak build, misalnya salinan kode yang dimaksudkan untuk menjalankan komputer yang hampir identik, file requirement.txt adalah cara populer untuk mengambil snapshot informasi dependensi yang tepat, di mana "install_requires" adalah cara yang baik untuk menangkap minimum dan versi kompatibel maksimum. Namun, mengingat bahwa mesin target hampir identik, saya sangat merekomendasikan membuat tarball dari seluruh awalan python. Ini bisa rumit, terlalu rinci untuk masuk ke sini. Periksa pip install
's --target
pilihan, atau virtualenv alias venv untuk memimpin.
kembali ke contoh
Dari foo / spam / eggs.py, jika kita menginginkan kode dari foo / baz kita bisa memintanya dengan namespace absolutnya:
import foo.baz
Jika kami ingin menyimpan kapabilitas untuk memindahkan eggs.py ke beberapa direktori lain di masa mendatang dengan beberapa baz
implementasi relatif lainnya , kami dapat menggunakan impor relatif seperti:
import ..baz
Untuk memuat kode python dengan andal, masukkan kode itu ke dalam modul, dan modul itu dipasang di pustaka python.
Modul yang diinstal selalu dapat dimuat dari namespace tingkat atas dengan import <name>
Ada proyek contoh hebat yang tersedia secara resmi di sini: https://github.com/pypa/sampleproject
Pada dasarnya, Anda dapat memiliki struktur direktori seperti ini:
the_foo_project/
setup.py
bar.py # `import bar`
foo/
__init__.py # `import foo`
baz.py # `import foo.baz`
faz/ # `import foo.faz`
__init__.py
daz.py # `import foo.faz.daz` ... etc.
.
Pastikan untuk menyatakan setuptools.setup()
di Anda setup.py
,
contoh resmi: https://github.com/pypa/sampleproject/blob/master/setup.py
Dalam kasus kami, kami mungkin ingin mengekspor bar.py
dan foo/__init__.py
, contoh singkat saya:
#!/usr/bin/env python3
import setuptools
setuptools.setup(
...
py_modules=['bar'],
packages=['foo'],
...
entry_points={},
# Note, any changes to your setup.py, like adding to `packages`, or
# changing `entry_points` will require the module to be reinstalled;
# `python3 -m pip install --upgrade --editable ./the_foo_project
)
.
Sekarang kita dapat menginstal modul kita ke pustaka python; dengan pip, Anda dapat menginstal the_foo_project
ke pustaka python Anda dalam mode edit, sehingga kami dapat bekerja secara real time
python3 -m pip install --editable=./the_foo_project
# if you get a permission error, you can always use
# `pip ... --user` to install in your user python library
.
Sekarang dari konteks python apa pun, kita dapat memuat py_modules dan paket bersama kita
#!/usr/bin/env python3
import bar
import foo
print(dir(bar))
print(dir(foo))
pip install --edit foo
, hampir selalu di dalam virtualenv. Saya hampir tidak pernah menulis modul yang tidak dimaksudkan untuk diinstal. jika saya salah mengerti sesuatu yang ingin saya ketahui.
editable
tautan telur dan modul python yang dipasang tidak persis sama dalam segala hal; misalnya, menambahkan namespace baru ke modul yang dapat diedit akan ditemukan di pencarian path Anda, tetapi jika itu tidak diekspor dalam file setup.py Anda tidak akan dikemas / diinstal! Uji kasus penggunaan Anda :)