การนำเข้าสัมพัทธ์ - ModuleNotFoundError: ไม่มีโมดูลชื่อ x


178

นี่เป็นครั้งแรกที่ฉันได้นั่งลงและลองใช้ python 3 และดูเหมือนจะล้มเหลวอย่างน่าสังเวช ฉันมีสองไฟล์ต่อไปนี้:

  1. test.py
  2. config.py

config.py มีฟังก์ชั่นบางอย่างที่กำหนดไว้ในนั้นรวมถึงตัวแปรบางอย่าง ฉันได้แยกมันออกเป็น:

config.py

debug = True

test.py

import config
print (config.debug)

ฉันยังมี __init__.py

อย่างไรก็ตามฉันได้รับข้อผิดพลาดต่อไปนี้:

ModuleNotFoundError: No module named 'config'

ฉันทราบว่าอนุสัญญา py3 นั้นใช้การนำเข้าแบบสัมบูรณ์:

from . import config

อย่างไรก็ตามสิ่งนี้นำไปสู่ข้อผิดพลาดต่อไปนี้:

ImportError: cannot import name 'config'

ดังนั้นฉันจะสูญเสียว่าจะทำอย่างไรที่นี่ ... ความช่วยเหลือใด ๆ ที่ชื่นชมอย่างมาก :)


ฉันไม่สามารถทำซ้ำข้อผิดพลาดคุณจะรันรหัสนี้ได้อย่างไร
Copperfield

2
ฉันใช้งานโดยไม่ได้ใช้งานซึ่งมาพร้อมกับ python และด้วยpython test.pyและมันก็ทำงานได้อย่างสมบูรณ์แบบ ฉันไม่มี pyCharm แต่อาจมีการกำหนดค่าบางอย่างที่ไม่ดีของ pyCharm ที่ทำให้เกิดปัญหา
Copperfield

1
แปลกมาก. ฉันใช้ WinPython เพียงดาวน์โหลด vanilla Python 3.6 จาก python.org และใช้งานได้ดี ไม่เคยคิดที่จะตรวจสอบล่าม! ขอบคุณ!
blitzmann

1
ฉันเดาว่าบางสิ่งที่ขี้ขลาดกำลังเกิดขึ้นกับ PYTHONPATH ตรวจสอบการตั้งค่า IDE และ / หรือตัวแปรสภาพแวดล้อมของระบบ
Martin Tournoij

1
ฉันมีปัญหาตรงนี้เหมือนกัน มันไม่ใช่ pycharm! มันคือ python3 มันทำงานได้ใน python2 แต่เมื่อใช้ python3 คุณจะเห็นข้อผิดพลาดนี้! น่าผิดหวังมาก

คำตอบ:


163

TL; DR:คุณไม่สามารถนำเข้าแบบสัมพัทธ์จากไฟล์ที่คุณดำเนินการได้เนื่องจาก__main__โมดูลไม่ได้เป็นส่วนหนึ่งของแพ็คเกจ

การนำเข้าแบบสัมบูรณ์ - นำเข้าสิ่งที่มีอยู่ในsys.path

การนำเข้าสัมพัทธ์ - นำเข้าบางสิ่งที่สัมพันธ์กับโมดูลปัจจุบันต้องเป็นส่วนหนึ่งของแพ็คเกจ

หากคุณใช้ทั้งสองรูปแบบในลักษณะเดียวกันหนึ่งในนั้นควรใช้งานได้ ต่อไปนี้เป็นตัวอย่างที่จะช่วยให้คุณเข้าใจว่าเกิดอะไรขึ้นเรามาเพิ่มอีกmain.pyไฟล์ด้วยโครงสร้างไดเรกทอรีโดยรวมดังนี้:

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

และขออัปเดต test.py เพื่อดูว่าเกิดอะไรขึ้น:

# 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

ให้เรียกใช้ test.py ก่อน:

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

นี่คือการทดสอบ "" เป็น__main__โมดูลและไม่ได้รู้อะไรเกี่ยวกับที่อยู่ในแพคเกจ อย่างไรก็ตามimport configควรใช้งานได้เนื่องจากryanโฟลเดอร์จะถูกเพิ่มใน sys.path

มารัน main.py แทน:

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

และนี่คือการทดสอบที่อยู่ในแพ็คเกจ "ryan" และสามารถดำเนินการนำเข้าแบบสัมพัทธ์ได้ import configล้มเหลวเนื่องจากไม่อนุญาตให้นำเข้าแบบสัมพัทธ์โดยนัยใน Python 3

หวังว่านี่จะช่วยได้

PS: ถ้าคุณติดกับ Python 3 ไม่จำเป็นต้องใช้__init__.pyไฟล์เพิ่มเติมอีก


3
มีสิ่งที่ฉันสามารถทำได้เพื่อให้การนำเข้าที่แน่นอนทำงานได้ตลอดเวลาหรือไม่ ชอบโทรsys.path.append('/some/path/my_module')ภายใน/some/path/my_module/__init__.pyหรือไม่
James T.

4
@JamesT ใช่มันเป็นเรื่องธรรมดาที่จะแก้ไขsys.pathในช่วงรันไทม์ ( github.com/… ) คุณยังสามารถตั้งค่าตัวแปรสภาพแวดล้อม PYTHONPATH
Igonato

6
"ถ้าคุณติดกับ Python 3 ไม่จำเป็นต้องใช้__init__.pyไฟล์" น่าสนใจ คุณสามารถทำอย่างละเอียดเกี่ยวกับเรื่องนี้? ฉันรู้สึกว่ากลไกการแก้ปัญหาแพคเกจไม่ได้เปลี่ยนแปลงมากนักระหว่างวันที่ 2 ถึง 3
เควิน

2
"ถ้าคุณติดกับ Python 3 ไม่จำเป็นต้องใช้__init__.pyไฟล์มากขึ้น" ในทางกลับกันคุณสามารถอธิบายสิ่งต่าง ๆ ได้ไหมถ้าเราต้องการให้แพ็คเกจทำงานได้ทั้ง 2 และ 3 และดู 2009 ที่__init__.pyเคราะห์ร้ายล้าสมัยมีไว้เพื่ออะไร? และคำตอบมากที่สุดที่ upvoted มัน"มันเป็นส่วนหนึ่งของแพคเกจ" เราจำเป็นต้องเริ่มเน้นความแตกต่าง"แพ็คเกจปกติ [เก่า, pre-3.3]" vs "แพ็คเกจเนมสเปซ [3.3+]"ทุกที่และบ่อยครั้ง
smci

61

ฉันคิดออก น่าผิดหวังมากโดยเฉพาะอย่างยิ่งมาจาก python2

คุณต้องเพิ่ม a .เข้ากับโมดูลโดยไม่คำนึงว่าสัมพันธ์กันหรือไม่แน่นอน

ฉันสร้างการตั้งค่าไดเรกทอรีดังนี้

/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()

เมื่อฉันเรียกใช้งานหลักนี่คือสิ่งที่เกิดขึ้น

$ 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'

ฉันวิ่ง 2to3 และผลลัพธ์หลักคือนี่

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

ฉันต้องแก้ไขคำสั่งการนำเข้าของ mody.py เพื่อแก้ไข

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


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

จากนั้นฉันก็รัน main.py อีกครั้งและได้ผลลัพธ์ที่คาดหวัง

$ python main.py
I gave you this string.

สุดท้ายเพียงทำความสะอาดและทำให้พกพาระหว่าง 2 และ 3

from __future__ import absolute_import
from .modx import does_something

1
น่าสังเกตว่าtry/exceptขั้นตอนการโหลดเป็นส่วนผสมจริงที่ใช้งานได้ที่นี่ (เป็นบางคนจะต้องใช้try:scripts.modxและexcept: modx) และเป็นสิ่งที่แก้ไขปัญหานี้สำหรับฉัน
Justapigeon

40

การตั้งค่า PYTHONPATH สามารถช่วยแก้ไขปัญหานี้ได้

นี่คือวิธีที่มันสามารถทำได้บน Windows

set PYTHONPATH=.


11
การตั้งค่า PYTHONPATH ไปยังไดเรกทอรีรหัสหลักแก้ปัญหาให้ฉันได้!
Geek

1
ทำงานได้ใน Linux เช่นกัน ส่งออก PYTHONPATH =
rjdkolb

29

PYTHONPATHคุณจะต้องผนวกเส้นทางโมดูลที่จะ


สำหรับ UNIX (Linux, OSX, ... )

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

สำหรับ Windows

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

4
ขอบคุณมาก @Giorgos! นี่เป็นเรื่องจริงโดยเฉพาะอย่างยิ่งเมื่อคุณพยายามตั้งค่าไดเรกทอรีรากในรูปภาพนักเทียบท่า
Tony Fraser

15

ลองตัวอย่างของคุณ

from . import config

มี SystemError ต่อไปนี้:
/usr/bin/python3.4 test.py
Traceback (การโทรล่าสุดครั้งล่าสุด):
ไฟล์ "test.py", บรรทัดที่ 1,
จาก import config
SystemError: ไม่ได้โหลดโมดูลหลัก '' ไม่สามารถทำการนำเข้าแบบสัมพัทธ์ได้


สิ่งนี้จะใช้ได้กับฉัน:

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

>>>debug=True

ทดสอบกับ Python: 3.4.2 - PyCharm 2016.3.2


ข้าง PyCharm นี้ให้คุณนำเข้าชื่อนี้
คุณต้องคลิกconfigและไอคอนวิธีใช้จะปรากฏขึ้น ป้อนคำอธิบายรูปภาพที่นี่


11

คุณสามารถเพิ่มไฟล์ต่อไปนี้ไปยังไดเรกทอรีการทดสอบของคุณแล้วหลามจะเรียกใช้ก่อนการทดสอบ

__init__.py file

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

นี่คือสิ่งที่ฉันกำลังมองหา ขอบคุณที่แบ่งปันคำตอบนี้ !!!
Mayur

การทำสิ่งนี้จะทำให้เกิดข้อผิดพลาด linter (pylint3) ข้อผิดพลาดคล้ายกับอันนี้ filename.py:12: C0413: นำเข้า "import abc.def.ghi.file_util as file_util" ควรวางไว้ที่ด้านบนของโมดูล (ตำแหน่งนำเข้าผิด)
Sharad

6

ตั้งค่าPYTHONPATHตัวแปรสภาพแวดล้อมในไดเรกทอรีโครงการราก

พิจารณา UNIX-like:

export PYTHONPATH=.

4

ตัวอย่างนี้ใช้ได้กับ Python 3.6

ฉันแนะนำให้ไปที่Run -> Edit ConfigurationsPyCharm ลบรายการใด ๆ ที่นั่นและพยายามเรียกใช้รหัสผ่าน PyCharm อีกครั้ง

หากไม่ได้ผลให้ตรวจสอบตัวแปลโครงการของคุณ (การตั้งค่า -> ตัวแปลโครงการ) และเรียกใช้การตั้งค่าเริ่มต้น (เรียกใช้ -> แก้ไขการกำหนดค่า ... )


4

ประกาศรายการsys.path ที่ถูกต้องก่อนที่คุณจะเรียกโมดูล:

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

ตามที่ระบุไว้ในความคิดเห็นของโพสต์ต้นฉบับดูเหมือนว่าจะมีปัญหากับตัวแปลภาษาไพ ธ อนที่ฉันใช้ไม่ว่าด้วยเหตุผลใดและไม่ใช่สิ่งผิดปกติกับสคริปต์ไพ ธ อน ฉันเปลี่ยนจากชุด WinPython เป็น python 3.6 อย่างเป็นทางการจาก python.org และใช้งานได้ดี ขอบคุณสำหรับทุกคนที่ช่วยเหลือ :)


1
อืมเกลียดที่จะพูดแบบนี้ แต่สิ่งเดียวกันก็เกิดขึ้นกับฉัน การสร้างสภาพแวดล้อมใหม่ช่วยแก้ไขปัญหา ในกรณีของฉันฉันได้รับข้อผิดพลาดนี้เมื่อทำการทดสอบ ในสภาพแวดล้อมเดียวกันพยายามนำเข้าโมดูลเดียวกันทำงาน สภาพแวดล้อมที่สร้างขึ้นใหม่ได้แก้ไขพวกเขาทั้งหมด (เวอร์ชั่นไพ ธ อนเดียวกัน 3.6)
naoko

1
IDE ที่แตกต่างกันมีวิธีการจัดการเส้นทางที่แตกต่างกันเป็นพิเศษสำหรับไฟล์ต้นฉบับของโครงการ (มุมมองโมดูลแม่แบบ ฯลฯ ) หากโครงการของคุณมีโครงสร้างและโค้ดอย่างถูกต้องแล้วมันควรจะทำงานกับ IDE ทั้งหมด (มาตรฐาน) มีปัญหากับ IDE ยอดนิยมเช่น WinPython หมายความว่าปัญหามาจากโครงการของคุณ ดังกล่าวข้างต้นปัญหาคือ "คุณต้องเพิ่ม. ไปยังโมดูล" โดย user3159377 ซึ่งควรเป็นคำตอบที่ยอมรับได้
winux

1

หากคุณใช้ python 3+ ให้ลองเพิ่มบรรทัดด้านล่าง

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

ลอง

from . import config

สิ่งที่นำเข้าจากระดับโฟลเดอร์เดียวกัน หากคุณพยายามนำเข้าโดยตรงถือว่าเป็นผู้ใต้บังคับบัญชา

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.