Python'un göreli ithalatını açıklayan var mı?


174

Hayatım boyunca python'un göreli ithalatını işe alamıyorum. Nerede çalışmıyor basit bir örnek oluşturduk:

Dizin yapısı:

/__init__.py
/start.py
/parent.py
/sub/__init__.py
/sub/relative.py

/start.py sadece içerir: import sub.relative

/sub/relative.py sadece içerir from .. import parent

Diğer tüm dosyalar boş.

Komut satırında aşağıdakileri yürütürken:

$ cd /
$ python start.py

Alırım:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/home/cvondrick/sandbox/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: Attempted relative import beyond toplevel package

Python 2.6 kullanıyorum. Neden böyle? Bu korumalı alan örneğini nasıl çalıştırabilirim?

Yanıtlar:


140

"Sub" paketinden içe aktarıyorsunuz. start.pybir __init__.pyhediye olsa bile paketin içinde değildir .

Programınızı bir dizinden yeniden başlatmanız gerekir parent.py:

./start.py

./pkg/__init__.py
./pkg/parent.py
./pkg/sub/__init__.py
./pkg/sub/relative.py

İle start.py:

import pkg.sub.relative

Şimdi pkg en üst düzey pakettir ve göreli içe aktarmanızın çalışması gerekir.


Mevcut düzeninize sadık kalmak istiyorsanız sadece kullanabilirsiniz import parent. start.pyTercümanınızı başlatmak için kullandığınız için, bulunduğunuz dizin start.pypython yolunuzdadır. parent.pyorada ayrı bir modül olarak yaşıyor.

__init__.pyDizin ağacının yukarısındaki bir betiğe hiçbir şey aktarmazsanız, en üst düzeyi güvenle silebilirsiniz .


2
'Modül' ve 'paket' terimlerini karıştırıyorsunuz. 'start.py' 'start', 'mod' ve 'mod.sub' modüllerini temsil eder, 'mod' en üst düzey bir pakettir.
Ferdinand Beyer

34
Teşekkürler, ama dürüst olmak gerekirse aptalca görünüyor. Böyle güzel bir dil için tasarımcıların böyle bir kısıtlama yaratacağına inanamıyorum. Başka yolu yok mu?
carl

2
Hiç saçma değil. Göreli ithalat, bir paket içindeki kardeş modüllerine atıfta bulunmak için bir araçtır. Bir üst düzey modülü içe aktarmak istiyorsanız, mutlak içe aktarımları kullanın.
Ferdinand Beyer

58
Aptal değil mi? Yani bash, ".." ile göreceli üst yön ele mümkün olamazdı?
e-satis

2
Bana öyle geliyor ki python'un fikri, ana komut dosyanızı başlattığınız dizinden "mutlak" içe aktarma kullanmaktır. Böylece üst modülü kardeşten almak için mutlak yol "üst öğeyi içe aktar" kullanabilirsiniz. Ve göreli ithalat bir tür miras ya da her türlü ..
Odysseus

35

relative.pyDoğrudan arayacaksanız , yani gerçekten bir üst düzey modülden içe aktarmak istiyorsanız, bunu açıkça sys.pathlisteye eklemeniz gerekir .
İşte nasıl çalışması gerekir:

# Add this line to the beginning of relative.py file
import sys
sys.path.append('..')

# Now you can do imports from one directory top cause it is in the sys.path
import parent

# And even like this:
from parent import Parent

Yukarıdakilerin bir çeşit tutarsızlığa neden olabileceğini düşünüyorsanız, bunun yerine bunu kullanabilirsiniz:

sys.path.append(sys.path[0] + "/..")

sys.path[0] giriş noktasının çalıştırıldığı yolu belirtir.


3

Python3'te kontrol etme:

python -V
Python 3.6.5

Örnek 1:

.
├── parent.py
├── start.py
└── sub
    └── relative.py

- start.py
import sub.relative

- parent.py
print('Hello from parent.py')

- sub/relative.py
from .. import parent

Bu şekilde çalıştırırsak (sadece PYTHONPATH'ın boş olduğundan emin olmak için):

PYTHONPATH='' python3 start.py

Çıktı:

Traceback (most recent call last):
  File "start.py", line 1, in <module>
    import sub.relative
  File "/python-import-examples/so-example-v1/sub/relative.py", line 1, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

İçeri aktarımı değiştirirsek sub/relative.py

- sub/relative.py
import parent

Eğer böyle çalıştırırsak:

PYTHONPATH='' python3 start.py

Çıktı:

Hello from parent.py

Örnek2:

.
├── parent.py
└── sub
    ├── relative.py
    └── start.py

- parent.py
print('Hello from parent.py')

- sub/relative.py
print('Hello from relative.py')

- sub/start.py
import relative
from .. import parent

Gibi çalıştırın:

PYTHONPATH='' python3 sub/start.py

Çıktı:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 2, in <module>
    from .. import parent
ValueError: attempted relative import beyond top-level package

İçe aktarma işlemini şu şekilde değiştirirsek sub/start.py:

- sub/start.py
import relative
import parent

Gibi çalıştırın:

PYTHONPATH='' python3 sub/start.py

Çıktı:

Hello from relative.py
Traceback (most recent call last):
  File "sub/start.py", line 3, in <module>
    import parent
ModuleNotFoundError: No module named 'parent'

Gibi çalıştırın:

PYTHONPATH='.' python3 sub/start.py

Çıktı:

Hello from relative.py
Hello from parent.py

Ayrıca kök klasörden içe aktarmayı kullanmak daha iyidir, yani:

- sub/start.py
import sub.relative
import parent

Gibi çalıştırın:

PYTHONPATH='.' python3 sub/start.py

Çıktı:

Hello from relative.py
Hello from parent.py
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.