Mengimpor dari jalur relatif dengan Python

Jawaban:

142

EDIT November 2014 (3 tahun kemudian):

Python 2.6 dan 3.x mendukung impor relatif yang tepat, di mana Anda dapat menghindari melakukan apa pun yang meretas. Dengan metode ini, Anda tahu bahwa Anda mendapatkan impor relatif daripada impor absolut . '..' artinya, buka direktori di atas saya:

from ..Common import Common

Sebagai peringatan, ini hanya akan berfungsi jika Anda menjalankan python Anda sebagai modul, dari luar paket. Sebagai contoh:

python -m Proj

Cara hacky asli

Metode ini masih umum digunakan dalam beberapa situasi, di mana Anda sebenarnya tidak pernah 'menginstal' paket Anda. Misalnya, ini populer dengan pengguna Django.

Anda dapat menambahkan Common / ke sys.path Anda (daftar jalur yang dilihat python untuk mengimpor sesuatu):

import sys, os
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'Common'))
import Common

os.path.dirname(__file__) hanya memberi Anda direktori tempat file python Anda saat ini, dan kemudian kami menavigasi ke 'Common /' direktori dan mengimpor 'Common' modul.

Dave
sumber
2
Jangan memodifikasi jalur modul python secara manual, mungkin hanya untuk peretasan cepat. Mempelajari manajemen paket Python menggunakan distutils, setuptools, dll. Biasanya merupakan keterampilan yang dibutuhkan untuk menyelesaikan masalah seperti itu.
Sascha Gottfried
1
@SaschaGottfried sangat setuju, meskipun jika Anda tidak membuat paket yang dapat didistribusikan, itu mungkin tidak masalah. Misalnya, di Django Anda tidak pernah benar-benar memasang aplikasi Anda dengan distutils, jadi metode di atas adalah cara yang mudah untuk diretas. Tapi bagaimanapun saya telah mengedit jawabannya dengan apa yang akan saya lakukan hari ini.
Dave
33
Terima kasih telah menjawab pertanyaan sebenarnya daripada berkhotbah tentang teknik yang benar. Ada banyak alasan bagus untuk melakukan impor relatif.
shrewmouse
bagaimana Anda akan naik lebih dari satu tingkat?
jxramos
10
untuk naik satu level lagi, gunakan titik tambahan untuk setiap level. @jxramos ex: from ...myfilepergi ke../../myfile
WattsInABox
10

Cukup lucu, masalah yang sama yang baru saja saya temui, dan saya mendapatkan pekerjaan ini dengan cara berikut:

menggabungkan dengan perintah linux ln, kita dapat membuat segalanya lebih sederhana:

1. cd Proj/Client
2. ln -s ../Common ./

3. cd Proj/Server
4. ln -s ../Common ./

Dan, sekarang jika Anda ingin mengimpor some_stuffdari file: Proj/Common/Common.pyke file Anda:, Proj/Client/Client.pyseperti ini:

# in Proj/Client/Client.py
from Common.Common import some_stuff

Dan, hal yang sama berlaku untuk Proj/Server, Juga berfungsi untuk setup.pyproses, pertanyaan yang sama dibahas di sini , semoga membantu!

jacoolee.dll
sumber
10

Jangan lakukan impor relatif.

Dari PEP8 :

Impor relatif untuk impor intra-paket sangat tidak dianjurkan.

Masukkan semua kode Anda ke dalam satu paket super (yaitu "myapp") dan gunakan subpaket untuk klien, server, dan kode umum.

Pembaruan: " Python 2.6 dan 3.x mendukung impor relatif yang tepat (...) ". Lihat jawaban Dave untuk lebih jelasnya.

Michał Šrajer
sumber
1
Bayangkan Anda menambahkan beberapa kode ke akhir klien dan server setelah baris ' if __name__ == "__main__":'. Artinya, Anda ingin dapat menggunakannya sebagai skrip yang berdiri sendiri. Bagaimana melakukannya dengan benar? Saya pikir itu kasus penggunaan umum yang harus didukung. Mengapa itu kecil hati?
Jabba
83
Saya terkejut bahwa "Jangan lakukan itu" adalah jawaban yang diterima untuk "bagaimana saya ..." pertanyaan (baik, kecuali untuk Rails <g>.) Ada yang alasan sesekali untuk melakukan hal ini. Saya menggunakan solusi yang mirip dengan apa yang disarankan Dave.
Tom Wilson
1
@ TomWilson: Ini tidak murni jawaban "jangan lakukan itu". Ada "lakukan dengan cara ini" di bawah.
Michał Šrajer
2
Seseorang harus memberi tahu orang-orang di Numpy! Mereka menggunakan BANYAK impor relatif!
Austin A
12
Jawaban ini tidak berlaku untuk versi Python saat ini. Bagian yang dikutip tidak lagi dapat ditemukan di PEP 8. Saat ini bunyinya seperti: "impor relatif eksplisit adalah alternatif yang dapat diterima untuk impor absolut, terutama ketika berurusan dengan tata letak paket yang kompleks di mana menggunakan impor absolut akan menjadi verbose yang tidak perlu"
moooeeeep
8

Melakukan impor relatif sama sekali tidak masalah! Inilah yang saya lakukan:

#first change the cwd to the script path
scriptPath = os.path.realpath(os.path.dirname(sys.argv[0]))
os.chdir(scriptPath)

#append the relative location you want to import from
sys.path.append("../common")

#import your module stored in '../common'
import common.py
Gary Beardsley
sumber
1
Tapi lebih baik Anda tahu di mana sys.argv [0] sebenarnya mengarah - itu (prolly) bukanlah direktori tempat Anda berada saat Anda memulai python.
CarlH
Ini adalah peretasan cepat, dengan banyak jebakan. Tapi pertanyaannya tidak lebih baik.
Sascha Gottfried
1
Ini tertulis dengan jelas, tetapi retasan asli dalam jawaban Dave lebih baik karena digunakan __file__untuk mendapatkan hubungan yang tepat dari file saat ini
John Neuhaus
4

Metode impor default sudah "relatif", dari PYTHONPATH. PYTHONPATH secara default, ke beberapa pustaka sistem bersama dengan folder dari file sumber asli. Jika Anda menjalankan dengan -m untuk menjalankan modul, direktori saat ini akan ditambahkan ke PYTHONPATH. Jadi jika titik masuk program Anda ada di dalam Proj, maka gunakanimport Common.Common seharusnya berfungsi di dalam Server.py dan Client.py.

Jangan lakukan impor relatif. Ini tidak akan berhasil seperti yang Anda inginkan.

Jonathan Sternberg
sumber
1
Jika ini benar, mengapa jawaban teratas tidak mengatakan ini? Apakah ini akan berhasil atau tidak?
Anonim