Bagaimana cara mengimpor modul Python yang diberikan jalur relatifnya?
Sebagai contoh, jika dirFoo
mengandung Foo.py
dan dirBar
, dan dirBar
mengandung Bar.py
, bagaimana cara mengimpor Bar.py
ke Foo.py
?
Berikut ini adalah representasi visual:
dirFoo\
Foo.py
dirBar\
Bar.py
Foo
ingin menyertakan Bar
, tetapi merestrukturisasi hierarki folder bukanlah suatu opsi.
python
relative-path
python-import
Jude Allred
sumber
sumber
Jawaban:
Dengan asumsi bahwa kedua direktori Anda adalah paket Python sungguhan (memiliki
__init__.py
file di dalamnya), berikut adalah solusi aman untuk penyertaan modul relatif ke lokasi skrip.Saya berasumsi bahwa Anda ingin melakukan ini, karena Anda perlu menyertakan satu set modul dengan skrip Anda. Saya menggunakan ini dalam produksi di beberapa produk dan bekerja di banyak skenario khusus seperti: skrip dipanggil dari direktori lain atau dieksekusi dengan python mengeksekusi alih-alih membuka juru bahasa baru.
Sebagai bonus, pendekatan ini memungkinkan Anda memaksa Python untuk menggunakan modul Anda, bukan yang diinstal pada sistem.
Peringatan! Saya tidak benar-benar tahu apa yang terjadi ketika modul saat ini ada di dalam
egg
file. Mungkin gagal juga.sumber
os.path.realpath(os.path.abspath(os.path.split(inspect.getfile( inspect.currentframe() ))[0]) + "/subfolder")
Do NOT menambahkan subfolder sebelumabspath
karena hal ini menyebabkan bug serius.cmd_subfolder
) langsung ke jawaban saya. Terima kasih!realpath
sudah menghasilkan jalur absolut, jadi saya tidak perluabspath
. Jugaos.path.dirname
dapat digunakan sebagai pengganti split, membuat pengindeksan[0]
menjadi usang. Barisnya adalah:os.path.realpath(os.path.dirname(inspect.getfile(inspect.currentframe())))
Pastikan dirBar memiliki
__init__.py
file - ini membuat direktori menjadi paket Python.sumber
sys.path
maka kehadiran__init__.py
didirBar
direktori tidak banyak membantu.__init.py__
hanya akan berfungsi ketika direktori sudah ada di sys.path dan dalam kasus saya tidak. Solusi oleh "sorin" (diterima) selalu bekerja.sys.path
pertanyaan? Mungkin ada sesuatu yang dihilangkan yang tidak kita lihat atau ketahui?Anda juga bisa menambahkan subdirektori ke jalur Python Anda sehingga impor sebagai skrip normal.
sumber
sys.path.append(os.path.dirname(__file__) + "/relative/path/to/module")
sys.path.append(__name__ if __name__ != '__main__' else __loader__.fullname)
sys.path.insert(0, <path to dirFoo>)
karena akan memuat modul ini sebelum modul dengan nama yang sama disimpan di tempat lain.sumber
os.path.join()
alih-alih bergabung dengan '/', yang akan merusak jendela (lumpuh).os.path.abspath(os.path.join(__file__,'..','lib'))
?Lakukan saja hal-hal sederhana untuk mengimpor file .py dari folder yang berbeda.
Katakanlah Anda memiliki direktori seperti:
Kemudian simpan saja file kosong di folder lib seperti namanya
Dan kemudian gunakan
Simpan
__init__.py
file di setiap folder hierarki modul impor.sumber
Jika Anda menyusun proyek Anda dengan cara ini:
Maka dari Foo.py Anda harus dapat melakukan:
Atau:
Per komentar Tom, ini mengharuskan
src
folder dapat diakses melaluisite_packages
jalur pencarian Anda. Juga, seperti yang ia sebutkan,__init__.py
secara implisit diimpor ketika Anda pertama kali mengimpor modul dalam paket / direktori tersebut. Biasanya__init__.py
hanyalah file kosong.sumber
from dirFoo import Foo
untuk mengatakanFoo.bla()
. Jika menggunakanimport dirFoo.Foo
satu harus menggunakandirFoo.Foo.bla()
- cukup jelek bahkan tanpa kasing unta.Metode termudah adalah dengan menggunakan sys.path.append ().
Namun, Anda mungkin juga tertarik dengan modul imp . Ini menyediakan akses ke fungsi impor internal.
Ini dapat digunakan untuk memuat modul secara dinamis ketika Anda tidak tahu nama modul.
Saya telah menggunakan ini di masa lalu untuk membuat antarmuka jenis plugin ke aplikasi, di mana pengguna akan menulis skrip dengan fungsi spesifik aplikasi, dan hanya meletakkan skrip mereka di direktori tertentu.
Juga, fungsi-fungsi ini mungkin berguna:
sumber
Ini adalah PEP yang relevan:
http://www.python.org/dev/peps/pep-0328/
Secara khusus, anggap dirFoo adalah direktori naik dari dirBar ...
Di dirFoo \ Foo.py:
sumber
Cara termudah tanpa modifikasi pada skrip Anda adalah dengan menetapkan variabel lingkungan PYTHONPATH. Karena sys.path diinisialisasi dari lokasi-lokasi ini:
Lari saja:
Anda sys.path akan berisi jalur di atas, seperti yang ditunjukkan di bawah ini:
sumber
Menurut pendapat saya pilihan terbaik adalah meletakkan __ init __.py di folder dan memanggil file
Tidak disarankan untuk menggunakan sys.path.append () karena ada sesuatu yang salah jika Anda menggunakan nama file yang sama dengan paket python yang ada. Saya belum mengujinya tetapi itu akan ambigu.
sumber
from dirBar.Bar import *
berhasil, tetapi tidakfrom dirBar.Bar import Bar
. apakah kamu tahu mengapa * bekerja? bagaimana jika saya mempunyai banyak file di dirBar / dan hanya ingin mengambil beberapa saja (menggunakan metode seperti yang Anda posting di sini)?from dirBar import Bar
.from
menunjukkan sumber, dan segala sesuatu setelahnyaimport
adalah apa yang harus diambil dari sumber itu.from dirBar.Bar import Bar
berarti "Dari sumber, impor sumber itu sendiri", yang tidak masuk akal. yang*
meskipun berarti, "memberi saya segalanya dari sumber"Cara cepat dan kotor untuk pengguna Linux
Jika Anda hanya bermain-main dan tidak peduli tentang masalah penyebaran, Anda dapat menggunakan tautan simbolis (dengan asumsi sistem file Anda mendukungnya) untuk membuat modul atau paket langsung terlihat di folder modul yang diminta.
atau
Catatan: "modul" adalah file apa pun dengan ekstensi .py dan "paket" adalah folder apa pun yang berisi file tersebut
__init__.py
(yang bisa berupa file kosong). Dari sudut pandang penggunaan, modul dan paket identik - keduanya mengekspos "definisi dan pernyataan" yang terkandung seperti yang diminta melaluiimport
perintah.Lihat: http://docs.python.org/2/tutorial/modules.html
sumber
dari pada:
kalau-kalau ada dirBar lain yang diinstal dan membingungkan pembaca foo.py.
sumber
Untuk kasus ini untuk mengimpor Bar.py ke Foo.py, pertama saya akan mengubah folder ini menjadi paket Python seperti:
Maka saya akan melakukannya seperti ini di Foo.py:
Jika saya ingin namespacing terlihat seperti Bar. terserah , atau
Jika saya ingin namespacing dirBar.Bar. terserahlah . Kasing kedua ini berguna jika Anda memiliki lebih banyak modul di bawah paket dirBar.
sumber
Tambahkan file __init__.py :
Kemudian tambahkan kode ini ke awal Foo.py:
sumber
dirBar
sudah merupakan paket Python (dengan adanyadirBar/__init__.py
), tidak perlu untuk menambahkandirBar
kesys.path
, tidak ada? Pernyataanimport Bar
dariFoo.py
harus cukup.Contoh sys.path relatif:
Berdasarkan jawaban ini .
sumber
Nah, seperti yang Anda sebutkan, biasanya Anda ingin memiliki akses ke folder dengan modul Anda relatif ke tempat skrip utama Anda dijalankan, sehingga Anda hanya mengimpornya.
Larutan:
Saya memiliki skrip
D:/Books/MyBooks.py
dan beberapa modul (seperti oldies.py). Saya perlu mengimpor dari subdirektoriD:/Books/includes
:Tempatkan
print('done')
dioldies.py
, jadi Anda memverifikasi semuanya berjalan OK. Cara ini selalu berhasil karena menurut definisi Pythonsys.path
seperti diinisialisasi pada saat startup program, item pertama dari daftar ini,path[0]
, adalah direktori yang berisi skrip yang digunakan untuk memanggil juru bahasa Python.Jika direktori skrip tidak tersedia (mis. Jika penerjemah dipanggil secara interaktif atau jika skrip dibaca dari input standar),
path[0]
adalah string kosong, yang mengarahkan Python untuk mencari modul dalam direktori saat ini terlebih dahulu. Perhatikan bahwa direktori skrip dimasukkan sebelum entri dimasukkan sebagai akibat dariPYTHONPATH
.sumber
site.addsitedir(sys.path[0]+'/includes')
) dalam program Python sederhana saya break_time.py: https://github.com/ltfschoen/PythonTest . Saya menggunakan sistem: MacOS v10.11.5, Python 2.7.12, IDLE IDE 2.7.12, Tk 8.5.9Cukup Anda bisa menggunakan:
from Desktop.filename import something
Contoh:
Kode:
Tetapi pastikan Anda membuat file kosong bernama "
__init__.py
" di direktori itusumber
import something
kemudian saya katakan untuk membuatnya lebih mudah*
pada dasarnya itu tidak baik untuk ram dan juga jika 2 fungsi memiliki nama yang sama itu akan menambah kode AndaSolusi lain adalah dengan menginstal paket py-butuhkan dan kemudian gunakan yang berikut di
Foo.py
sumber
require()
fungsi, Anda dapat melihat proyek Node.py saya: github.com/nodepy/nodepyBerikut cara mengimpor file dari satu tingkat di atas, menggunakan jalur relatif.
Pada dasarnya, cukup pindahkan direktori kerja ke atas (atau lokasi relatif apa pun), tambahkan itu ke jalur Anda, lalu pindahkan direktori kerja kembali ke tempat awalnya.
sumber
Saya tidak berpengalaman tentang python, jadi jika ada yang salah dengan kata-kata saya, katakan saja. Jika hierarki file Anda diatur seperti ini:
module_1.py
mendefinisikan fungsi yang disebutfunc_1()
, module_2.py :dan Anda menjalankan
python module_2.py
dalam cmd, itu akan menjalankan apa yangfunc_1()
mendefinisikan. Biasanya itulah cara kami mengimpor file hierarki yang sama. Tetapi ketika Anda menulisfrom .module_1 import func_1
dimodule_2.py
, python interpreter akan mengatakanNo module named '__main__.module_1'; '__main__' is not a package
. Jadi untuk memperbaikinya, kita hanya menyimpan perubahan yang baru saja kita buat, dan memindahkan kedua modul ke sebuah paket, dan menjadikan modul ketiga sebagai penelepon untuk dijalankanmodule_2.py
.main.py :
Tapi alasan kita menambahkan
.
sebelummodule_1
dimodule_2.py
adalah bahwa jika kita tidak melakukan itu dan larimain.py
, python interpreter akan mengatakanNo module named 'module_1'
, itu sedikit rumit,module_1.py
tepat di sampingmodule_2.py
. Sekarang aku membiarkanfunc_1()
dalammodule_1.py
do sesuatu:yang
__name__
merekam siapa yang memanggil func_1. Sekarang kita simpan.
sebelumnyamodule_1
, jalankanmain.py
, itu akan mencetakpackage_1.module_1
, bukanmodule_1
. Ini menunjukkan bahwa orang yang memanggilfunc_1()
berada pada hierarki yang sama denganmain.py
, yang.
menyiratkan yangmodule_1
berada pada hierarki yang sama denganmodule_2.py
dirinya. Jadi, jika tidak ada titik,main.py
akan mengenalimodule_1
hierarki yang sama dengan dirinya, ia dapat mengenalipackage_1
, tetapi bukan apa yang "di bawah" itu.Sekarang mari kita membuatnya agak rumit. Anda memiliki
config.ini
dan modul mendefinisikan fungsi untuk membacanya di hierarki yang sama dengan 'main.py'.Dan untuk beberapa alasan yang tidak dapat dihindari, Anda harus memanggilnya
module_2.py
, sehingga harus mengimpor dari hierarki atas. module_2.py :Dua titik berarti impor dari hierarki atas (tiga titik akses atas dari atas, dan seterusnya). Sekarang kita jalankan
main.py
, penafsir akan berkata:ValueError:attempted relative import beyond top-level package
. "Paket tingkat atas" di sini adalahmain.py
. Hanya karenaconfig.py
ada di sampingmain.py
, mereka berada di hierarki yang sama,config.py
tidak "di bawah"main.py
, atau tidak "dipimpin" olehmain.py
, jadi itu di luarmain.py
. Untuk memperbaikinya, cara paling sederhana adalah:Saya pikir itu bertepatan dengan prinsip mengatur hierarki file proyek, Anda harus mengatur modul dengan fungsi yang berbeda di folder yang berbeda, dan hanya meninggalkan pemanggil teratas di luar, dan Anda dapat mengimpor sesuka Anda.
sumber
Ini juga berfungsi, dan jauh lebih sederhana daripada apa pun dengan
sys
modul:sumber
Panggil saya terlalu berhati-hati, tapi saya suka membuat saya lebih portabel karena tidak aman untuk menganggap bahwa file akan selalu berada di tempat yang sama di setiap komputer. Secara pribadi saya memiliki kode mencari jalur file terlebih dahulu. Saya menggunakan Linux sehingga milik saya akan terlihat seperti ini:
Itu tentu saja kecuali jika Anda berencana untuk mengemasnya bersama-sama. Tetapi jika itu masalahnya Anda tidak benar-benar membutuhkan dua file terpisah.
sumber