Python“ImportError:No module named”问题

17

我在Windows XP SP3上运行Python 2.6.1。我的IDE是PyCharm 1.0-Beta 2 build PY-96.1055。

我将.py文件存储在名为"src"的目录中;它有一个名为__init__.py的文件,除了顶部的"__author__"属性之外,它是空的。

其中之一被称为Matrix.py:

#!/usr/bin/env python
"""
"Core Python Programming" chapter 6.
A simple Matrix class that allows addition and multiplication
"""
__author__ = 'Michael'
__credits__ = []
__version__ = "1.0"
__maintainer__ = "Michael"
__status__ = "Development"

class Matrix(object):
    """
    exercise 6.16: MxN matrix addition and multiplication
    """
    def __init__(self, rows, cols, values = []):
        self.rows = rows
        self.cols = cols
        self.matrix = values

    def show(self):
        """ display matrix"""
        print '['
        for i in range(0, self.rows):
            print '(',
            for j in range(0, self.cols-1):
                print self.matrix[i][j], ',',
            print self.matrix[i][self.cols-1], ')'
        print ']'

    def get(self, row, col):
        return self.matrix[row][col]

    def set(self, row, col, value):
        self.matrix[row][col] = value

    def rows(self):
        return self.rows

    def cols(self):
        return self.cols

    def add(self, other):
        result = []
        for i in range(0, self.rows):
            row = []
            for j in range(0, self.cols):
                row.append(self.matrix[i][j] + other.get(i, j))
            result.append(row)
        return Matrix(self.rows, self.cols, result)

    def mul(self, other):
        result = []
        for i in range(0, self.rows):
            row = []
            for j in range(0, other.cols):
                sum = 0
                for k in range(0, self.cols):
                    sum += self.matrix[i][k]*other.get(k,j)
                row.append(sum)
            result.append(row)
        return Matrix(self.rows, other.cols, result)

    def __cmp__(self, other):
        """
        deep equals between two matricies
        first check rows, then cols, then values
        """
        if self.rows != other.rows:
            return self.rows.cmp(other.rows)
        if self.cols != other.cols:
            return self.cols.cmp(other.cols)
        for i in range(0, self.rows):
            for j in range(0, self.cols):
                if self.matrix[i][j] != other.get(i,j):
                    return self.matrix[i][j] == (other.get(i,j))
        return True # if you get here, it means size and values are equal



if __name__ == '__main__':
    a = Matrix(3, 3, [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
    b = Matrix(3, 3, [[6, 5, 4], [1, 1, 1], [2, 1, 0]])
    c = Matrix(3, 3, [[2, 0, 0], [0, 2, 0], [0, 0, 2]])
    a.show()
    b.show()
    c.show()
    a.add(b).show()
    a.mul(c).show()

我创建了一个名为 "test" 的新目录,它还有一个 __init__.py 文件,在顶部只有一个 "__author__" 属性。我创建了一个 MatrixTest.py 来对我的 Matrix 类进行单元测试:

#!/usr/bin/env python
"""
Unit test case for Matrix class
See http://jaynes.colorado.edu/PythonGuidelines.html#module_formatting for Python coding guidelines
"""

import unittest #use my unittestfp instead for floating point
from src import Matrix # Matrix class to be tested

__author__ = 'Michael'
__credits__ = []
__license__ = "GPL"
__version__ = "1.0"
__maintainer__ = "Michael"
__status__ = "Development"

class MatrixTest(unittest.TestCase):
    """Unit tests for Matrix class"""
    def setUp(self):
        self.a = Matrix.Matrix(3, 3, [[1, 2, 3], [4, 5, 6], [7, 8, 9]])
        self.b = Matrix.Matrix(3, 3, [[6, 5, 4], [1, 1, 1], [2, 1, 0]])
        self.c = Matrix.Matrix(3, 3, [[2, 0, 0], [0, 2, 0], [0, 0, 2]])

    def testAdd(self):
        expected = Matrix.Matrix(3, 3, [[7, 7, 7], [5, 6, 7], [9, 9, 9]])    # need to learn how to write equals for Matrix
        self.a.add(self.b)
        assert self.a == expected

if __name__ == '__main__':    #run tests if called from command-line
    suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
    unittest.TextTestRunner(verbosity=2).run(suite)

但是当我尝试运行我的MatrixTest时,出现了这个错误:

C:\Tools\Python-2.6.1\python.exe "C:/Documents and Settings/Michael/My Documents/Projects/Python/learning/core/test/MatrixTest.py"
Traceback (most recent call last):
  File "C:/Documents and Settings/Michael/My Documents/Projects/Python/learning/core/test/MatrixTest.py", line 8, in <module>
    from src import Matrix # Matrix class to be tested
ImportError: No module named src

Process finished with exit code 1

根据我所阅读的所有内容,我知道将init.py文件放在所有目录中可以解决这个问题。

如果有人能指出我错过了什么,我会非常感激。

我还想寻求关于开发和维护源代码和单元测试类的最佳建议。 我考虑采用编写Java时通常使用的方式:/src和/test目录,具有相同的包结构。 这种思考方法是否符合"Pythonic",或者我应该考虑其他组织方案?

更新:

感谢那些回答我的人,以下是为我解决问题的解决方案:

  1. 将import更改为from src import Matrix #Matrix class to be tested
  2. sys.path作为环境变量添加到我的unittest配置中,以分号分隔./src和./test目录。
  3. 按照所示更改MatrixTest.py中的声明。

你说你的文件存储在src文件夹中?C:\ Tools \ Python-2.6.1 \ python.exe“C:/ Documents and Settings / Michael / My Documents / Projects / Python / learning / core / test / MatrixTest.py” - awithrow
1
使用python -m test.MatrixTest。请参考https://dev59.com/tWAf5IYBdhLWcg3wdCh1。 - jrc
2个回答

17
我猜测您需要将更改PYTHONPATH环境变量,以包括src和test目录。在src目录中运行程序可能有效,因为Python会自动将当前正在运行的脚本所在的目录插入到sys.path中。因此,在src中导入模块只要同时执行一个位于src中的脚本就可以工作。但现在您正在从test运行脚本,test目录会自动添加到sys.path中,而src则不会。PYTHONPATH中列出的所有目录都会添加到sys.path中,并且Python会搜索sys.path以查找模块。另外,如果您说
from src import Matrix

那么Matrix将会指向这个包,你需要使用Matrix.Matrix来访问这个类。


@Cristian:我在一个名为test.py的文件中放置了import sys; print(sys.path)。然后我运行了cd /some/other/dir; python /path/to/test.py。列出的第一个路径是/path/to,而不是/some/other/dir。因此,似乎添加到sys.path的是脚本所在的目录,而不是当前工作目录(CWD)。 - unutbu
@~unutbu:你说得对!我发表评论的原因是来自教程中的这段代码:“当导入名为spam的模块时,解释器会在当前目录中搜索名为spam.py的文件,然后在由环境变量PYTHONPATH指定的目录列表中搜索。”我想有人应该用不那么含糊的方式重新表述它。 - Cristian Ciupitu
1
@Cristian:嗯,那确实有点令人困惑(不过第二段试图澄清)。 这是另一个链接到文档的地址; 我认为这个更清晰:http://docs.python.org/library/sys.html#sys.path - unutbu
谢谢你,~unutbu。你和Christian Ciupitu带我找到的解决方案已经添加到我的问题中了。 - duffymo
@~unutbu:是的,第二段澄清了一些事情,虽然我很久以前读过教程,但它并不存在或者我不知道怎么跳过它。无论如何,我向文档团队报告了这个问题,也许他们会重新表述那一部分,使其更加清晰明了。另外,感谢 sys.path 的链接! - Cristian Ciupitu

1
关于最佳实践,PycURL 在与主源代码相同的级别上使用一个名为tests的目录。另一方面,像Twistedsorl-thumbnail这样的项目在主源代码下使用一个名为test(s)的子目录。
问题的另一半已经被~unutbu回答了。

1
嗨,Christian,谢谢你的示例。我更喜欢你的做法:/src和/test在同一级别。 - duffymo

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接