首页 > 解决方案 > Python:尝试从另一个编码 .py 文件导入模块时出现“ModuleNotFoundError”

问题描述

我在 MacBook Pro(13 英寸,2016 年,两个 Thunderbolt 3 端口)上使用 Python 3.8.3

我目前正在建立一个在线聊天,这是我的 person.py 代码:

class Person:

    """
    Represents a person, hold name, socket client and client addr
    """
    def __init__(self, addr, client):
        self.addr = addr
        self.client = client
        self.name = None

    def set_name(self, name):
        self.name = name

    def __repr__(self):
        return f"Person({self.addr}, {self.name})"

这是我的 server.py 编码:

from threading import Thread
import time
from person import Person

# GLOBAL CONSTANTS
HOST = 'localhost'
PORT = 5500
ADDR = (HOST, PORT)
MAX_CONNECTIONS = 10
BUFSIZ = 512

# GLOBAL VARIABLES
persons = []
SERVER = socket(AF_INET, SOCK_STREAM)
SERVER.bind(ADDR)  # set up server

def broadcast(msg, name):
    """
    send new messages to all clients
    :param msg: bytes["utf8"]
    :param name: str
    :return:
    """
    for person in persons:
        client = person.client
        client.send(bytes(name, "utf8") + msg)


def client_communication(person):
    """
    Thread to handle all messages from client
    :param person: Person
    :return: None
    """
    client = person.client

    # get persons name
    name = client.recv(BUFSIZ).decode("utf8")
    person.set_name(name)
    msg = bytes(f"{name} has joined the chat!", "utf8")
    broadcast(msg, "")  # broadcast welcome message


    while True:
        try:
            msg = client.recv(BUFSIZ)

            if msg == bytes("{quit}", "utf8"):
                client.close()
                persons.remove(person)
                broadcast(f"{name} has left the chat...", "")
                print(f"[DISCONNECTED] {name} disconnected")
                break
            else:
                broadcast(msg, name+": ")
                print(f"{name}: ", msg.decode("utf8"))

        except Exception as e:
            print("[EXCEPTION]", e)
            break


def wait_for_connection():
    """
    Wait for connetion from new clients, start new thread once connected
    :param SERVER: SOCKET
    :return: None
    """
    run = True
    while run:
        try:
            client, addr = SERVER.accept()
            person = Person(addr, client)
            persons.append(person)
            print(f"[CONNECTION] {addr} connected to the server at {time.time()}")
            Thread(target=client_communication, args=(person,)).start()
        except Exception as e:
            print("[EXCEPTION]", e)
            run = False

    print("SERVER CRASHED")


if __name__ == "__main__":
    SERVER.listen(MAX_CONNECTIONS)  # listen for connections
    print("[STARTED] Waiting for connections...")
    ACCEPT_THREAD = Thread(target=wait_for_connection)
    ACCEPT_THREAD.start()
    ACCEPT_THREAD.join()
    SERVER.close()

问题是,每次我尝试运行程序时,它都会给我这个错误:

    from person import Person
ModuleNotFoundError: No module named 'person'

有人知道如何解决这个问题吗?

标签: pythonpython-3.x

解决方案


问题

这很可能是寻路错误。Python 路径将在安装libsite-packages文件夹中查找。它还将查看当前工作目录。因此,如果您从另一个文件夹运行一个文件但尝试导入某些内容,它将在您的运行目录中查找,而不是您正在运行的文件所在的位置。这里有两个解决这个问题的方法。

第一个解决方案

您可以使工作目录与您正在运行的文件相同。给出以下文件结构:

workingdir
+-- thecode
    |-- server.py
    +-- person.py

您有当前工作目录,也就是您运行命令的位置,workingdir因此终端可能如下所示:

workingdir % python thecode/server.py

因此,您需要将工作目录更改为thecode。去做到cd thecode那里。

第二种解决方案

您可以改为将文件的目录添加到 python 路径。这保存在 sys.path 中,并在每次 python 运行结束时获取。因此,最好在server.py文件开头添加路径,以便person.py在导入之前在路径中。使用类似于以下代码的代码来执行此操作。

import sys
import os.path
sys.path.append(os.path.split(os.path.abspath(__file__))[0])

# now you may import Person.
from person import Person

前两个模块sysos非常标准,将为您提供附加到 Python 路径的工具。os.path.abspath获取当前文件的绝对路径,在本例中为server.py. 然后os.path.split将获得绝对路径的尾部(所有目录)和头部(文件名)。最后附加到sys.path允许 Pythonperson.py在您的文件目录中查找。

其他解决方案(在这种情况下可能不会使用)

您还可以创建自定义 Python 包并使用pip. 这在这种情况下不是很有用,因为导入问题只是一个文件,但是,如果您想创建一个其他人可能使用的自定义 Python 项目,这篇 Python 文档文章会有所帮助

最终的解决方案(诚然,我曾经这样做并且不是最好的解决方法)是将您的文件放在 Python 路径中已经存在的文件夹中。在这种情况下,它可能是lib文件夹。对我来说,运行 Python 3.8 的路径是/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8,对于任何 Python 3.x 版本,这将是相同的,但版本被替换了。Python 2.x 有时有不同的位置。


推荐阅读