Göreli içe aktarmalar - ModuleNotFoundError: x adlı modül yok


179

Bu gerçekten oturdum ve python 3 denedim ve sefil başarısız gibi görünüyor. Aşağıdaki iki dosya var:

  1. test.py
  2. config.py

config.py içinde tanımlanmış birkaç fonksiyonun yanı sıra birkaç değişken vardır. Aşağıdakilere çıkardım:

config.py

debug = True

test.py

import config
print (config.debug)

Ayrıca bir __init__.py

Ancak, aşağıdaki hatayı alıyorum:

ModuleNotFoundError: No module named 'config'

Py3 kuralının mutlak ithalatı kullanmak olduğunun farkındayım:

from . import config

Ancak, bu aşağıdaki hataya yol açar:

ImportError: cannot import name 'config'

Bu yüzden burada ne yapacağım konusunda bir kaybım var ... Herhangi bir yardım çok takdir ediliyor. :)


Hatayı yeniden oluşturamıyorum, bu kodu nasıl çalıştırıyorsunuz?
Copperfield

2
Ben python ile gelen boşta yürütmek, ve aynı zamanda python test.py, ve mükemmel çalışıyor. PyCharm'ım yok, ancak soruna neden olan pyCharm'ın bazı kötü yapılandırması olabilir
Copperfield

1
Çok tuhaf. WinPython kullanıyorum - sadece python.org'dan vanilla Python 3.6'yı indirin ve iyi çalışıyor. Tercümanı kontrol etmeyi hiç düşünmemiştim! Teşekkürler!
blitzmann

1
Tahminimce PYTHONPATH ile korkak bir şeyler oluyor. IDE ayarlarınızı ve / veya sistem ortamı değişkenlerinizi kontrol edin.
Martin Tournoij

1
Aynı problemim var. Pycharm değil! Python3. Python2'de çalışır, ancak python3 kullanırken bu hatayı görürsünüz! çok sinir bozucu.

Yanıtlar:


166

TL; DR: Eğer dosyadan göreli ithalat yapamaz yürütmek beri __main__modül bir paketin bir parçası değildir.

Mutlak ithalat - mevcut bir şeyi içe aktarınsys.path

Göreli ithalatlar - mevcut modüle göre bir şey içe aktarma, bir paketin parçası olmalıdır

Her iki varyantı da aynı şekilde çalıştırıyorsanız, bunlardan biri çalışmalıdır. Her neyse, burada neler olduğunu anlamanıza yardımcı olacak bir örnek main.py, genel dizin yapısına sahip başka bir dosya ekleyelim :

.
./main.py
./ryan/__init__.py
./ryan/config.py
./ryan/test.py

Neler olup bittiğini görmek için test.py dosyasını güncelleyelim:

# config.py
debug = True


# test.py
print(__name__)

try:
    # Trying to find module in the parent package
    from . import config
    print(config.debug)
    del config
except ImportError:
    print('Relative import failed')

try:
    # Trying to find module on sys.path
    import config
    print(config.debug)
except ModuleNotFoundError:
    print('Absolute import failed')
# main.py
import ryan.test

Önce test.py'yi çalıştıralım:

$ python ryan/test.py
__main__
Relative import failed
True

İşte "test" olduğunu__main__ modülü ve bir paket ait hakkında hiçbir şey bilmiyor. Ancak import configbu yana, çalışması gerekir ryanklasör sys.path eklenecektir.

Bunun yerine main.py'yi çalıştıralım:

$ python main.py
ryan.test
True
Absolute import failed

Ve burada test "ryan" paketinin içindedir ve göreceli ithalat yapabilir. import configPython 3'te örtük göreli içe aktarmaya izin verilmediğinden başarısız olur.

Umarım bu yardımcı olmuştur.

Not: Python 3 ile yapıyorsanız, __init__.pydosyalara artık gerek yoktur .


3
Mutlak ithalatın her zaman işe yaramasını sağlamak için yapabileceğim bir şey var mı? Gibi, sys.path.append('/some/path/my_module')içinde ara /some/path/my_module/__init__.py?
James T.

4
@JamesT. Evet, sys.pathçalışma zamanı sırasında değişiklik yapmak oldukça yaygındır ( github.com/… ). PYTHONPATH ortam değişkenini de ayarlayabilirsiniz.
Igonato

6
"Python 3 ile uğraşıyorsanız __init__.pydosyalara artık ihtiyaç kalmaz ." İlginç. Bu konuyu biraz açıklayabilir misiniz? Paket çözümleme mekanizmasının 2 ile 3 arasında çok fazla değişmediği izlenimindeydim.
Kevin

2
"Python 3 ile yapıyorsanız, __init__.pydosyalara artık gerek kalmaz ." Tersine, bir paketin hem 2 hem de 3'te çalışmasını istiyorsak, şeyleri açıklayabilir misiniz? Ve 2009 tarihli acımasızca esinti ne __init__.pyiçin? ve en çok beğenilen cevabı "Bu bir paketin parçası" . Her yerde ve sıklıkla "normal paket [eski, 3.3 öncesi]" vs "ad alanı paketi [3.3+]" ayrımını vurgulamaya başlamalıyız .
smci

61

Bunu anladım. Çok sinir bozucu, özellikle python2 geliyor.

.Modüle göreceli veya mutlak olup olmadığına bakılmaksızın a eklemeniz gerekir .

Dizin kurulumunu aşağıdaki gibi oluşturdum.

/main.py
--/lib
  --/__init__.py
  --/mody.py
  --/modx.py

modx.py

def does_something():
    return "I gave you this string."

mody.py

from modx import does_something

def loaded():
    string = does_something()
    print(string)

main.py

from lib import mody

mody.loaded()

Main'i yürüttüğümde olan budur

$ python main.py
Traceback (most recent call last):
  File "main.py", line 2, in <module>
    from lib import mody
  File "/mnt/c/Users/Austin/Dropbox/Source/Python/virtualenviron/mock/package/lib/mody.py", line 1, in <module>
    from modx import does_something
ImportError: No module named 'modx'

2'ye 3 koştum ve çekirdek çıktı bu

RefactoringTool: Refactored lib/mody.py
--- lib/mody.py (original)
+++ lib/mody.py (refactored)
@@ -1,4 +1,4 @@
-from modx import does_something
+from .modx import does_something

 def loaded():
     string = does_something()
RefactoringTool: Files that need to be modified:
RefactoringTool: lib/modx.py
RefactoringTool: lib/mody.py

Düzeltmek için mody.py's import deyimini değiştirmek zorunda kaldım

try:
    from modx import does_something
except ImportError:
    from .modx import does_something


def loaded():
    string = does_something()
    print(string)

Sonra main.py'yi tekrar çalıştırdım ve beklenen çıktıyı aldım

$ python main.py
I gave you this string.

Son olarak, sadece temizlemek ve 2 ve 3 arasında taşınabilir hale getirmek için.

from __future__ import absolute_import
from .modx import does_something

1
Worth belirterek try/exceptyükleme prosedürü (bazı insanlar kullanmanız gerekecektir olarak burada çalışıyor gerçek bileşendir try:scripts.modxve except: modx) ve benim için bu sorunu çözmüş buydu.
Justapigeon

40

PYTHONPATH ayarı da bu soruna yardımcı olabilir.

Windows'ta nasıl yapılabileceği aşağıda açıklanmıştır

set PYTHONPATH=.


11
PYTHONPATH'ı ana kod dizinine ayarlamak benim için problemi çözdü!
Geek

1
Linux'ta da çalışır. ihracat PYTHONPATH =.
rjdkolb

29

Modülün yolunu eklemeniz gerekir PYTHONPATH.


UNIX için (Linux, OSX, ...)

export PYTHONPATH="${PYTHONPATH}:/path/to/your/module/"

Pencereler için

set PYTHONPATH=%PYTHONPATH%;C:\path\to\your\module\

4
Büyük teşekkürler @ Giorgos! Bu, özellikle bir docker görüntüsünde kök dizin ayarlamaya çalıştığınızda geçerlidir.
Tony Fraser

15

Örneğini denedim

from . import config

şu SystemError'ı aldı:
/usr/bin/python3.4 test.py Geri
izleme (en son çağrı son):
"test.py" dosyası, satır 1, '
den. import config
SystemError: Ana modül '' yüklü değil, göreceli içe aktarma gerçekleştiremiyor


Bu benim için işe yarayacak:

import config
print('debug=%s'%config.debug)

>>>debug=True

Python ile test edilmiştir: 3.4.2 - PyCharm 2016.3.2


Bunun yanında PyCharm size bu ismi almanızı önerir .
Tıklamanız gerekiyor configve bir yardım simgesi beliriyor. resim açıklamasını buraya girin


11

Test dizininize aşağıdaki dosyayı ekleyebilir ve ardından python, testlerden önce çalıştıracaktır

__init__.py file

import os
import sys
sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))

Tam da aradığım şey buydu. Bu yanıtı paylaştığınız için teşekkürler !!!
Mayur

Böyle bir şey yapılması linter (pylint3) hatası verir. Hata buna benzer. dosyaadı.py:12:0: C0413: "import abc.def.ghi.file_util dosyasını file_util olarak içe aktar" modülün en üstüne yerleştirilmelidir (yanlış alma konumu)
Sharad

6

PYTHONPATHKök proje dizininde ortam değişkenini ayarlayın .

UNIX benzeri göz önüne alındığında:

export PYTHONPATH=.

4

Bu örnek Python 3.6 üzerinde çalışır.

Söyleyecektim önermek Run -> Edit Configurationsorada herhangi bir girdi silerek pycharm içinde ve yine pycharm aracılığıyla kod çalıştırmaya çalışırken.

Bu işe yaramazsa, proje yorumcunuzu (Ayarlar -> Proje Yorumlayıcısı) kontrol edin ve yapılandırma varsayılanlarını çalıştırın (Çalıştır -> Yapılandırmaları Düzenle ...).


4

Modülü çağırmadan önce doğru sys.path listesini bildirin :

import os, sys

#'/home/user/example/parent/child'
current_path = os.path.abspath('.')

#'/home/user/example/parent'
parent_path = os.path.dirname(current_path)

sys.path.append(parent_path)
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'child.settings')

1

Orijinal yazının yorumlarında belirtildiği gibi, bu, herhangi bir nedenle kullandığım python yorumlayıcısıyla ilgili bir sorun gibi görünüyordu ve python komut dosyalarında yanlış bir şey değil. WinPython paketinden python.org'dan resmi python 3.6'ya geçtim ve gayet iyi çalıştı. herkese yardım için teşekkürler :)


1
Hmm bunu söylemekten nefret ediyorum ama aynı şey bana da oldu. Yeniden ortam oluşturmak sorunu giderir. Benim durumumda, testleri çalıştırırken bu hatayı alıyordum. Aynı ortamda, aynı modülü ithal etmeye çalışıldı. Rekreasyon ortamı hepsini düzeltti (aynı python sürüm 3.6)
naoko

1
Farklı IDE'lerin, özellikle proje kaynak dosyaları (görünümler, modüller, şablonlar, vb.) İçin yolların farklı şekilde işlenmesi mümkündür. Projeniz düzgün yapılandırılmış ve kodlanmışsa, tüm (standart) IDE'lerle çalışmalıdır. WinPython gibi popüler IDE'lerle ilgili sorunlara sahip olmak, sorunun gerçekten projenizden kaynaklandığı anlamına gelir. Yukarıda belirtildiği gibi sorun user3159377 tarafından kabul edilen cevap olması gereken "modüle bir.
winux

1

Python 3+ kullanıyorsanız aşağıdaki satırları eklemeyi deneyin

import os, sys
dir_path = os.path.dirname(os.path.realpath(__file__))
parent_dir_path = os.path.abspath(os.path.join(dir_path, os.pardir))
sys.path.insert(0, parent_dir_path)

0

Deneyin

from . import config

Bunun yaptığı, aynı klasör düzeyinden içe aktarmadır. Doğrudan içe aktarmaya çalışırsanız, bunun bir alt öğe olduğunu varsayar.

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.