我以两种不同的方式导入了一个numpy
库。第一次与from numpy.random import mtrand
,第二次与sys.path
搞砸后.
但是,这两个模块导入的输出完全不同:
>>> from numpy.random import mtrand
>>> dir(mtrand)
['RandomState', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__test__', '_rand', 'beta', 'binomial', 'bytes', 'chisquare', 'dirichlet', 'exponential', 'f', 'gamma', 'geometric', 'get_state', 'gumbel', 'hypergeometric', 'laplace', 'logistic', 'lognormal', 'logseries', 'multinomial', 'multivariate_normal', 'negative_binomial', 'noncentral_chisquare', 'noncentral_f', 'normal', 'np', 'pareto', 'permutation', 'poisson', 'power', 'rand', 'randint', 'randn', 'random_integers', 'random_sample', 'rayleigh', 'seed', 'set_state', 'shuffle', 'standard_cauchy', 'standard_exponential', 'standard_gamma', 'standard_normal', 'standard_t', 'triangular', 'uniform', 'vonmises', 'wald', 'weibull', 'zipf']
第二个:
>>> sys.path.insert(0, '/usr/lib/pymodules/python2.7/numpy/random')
>>> import mtrand
>>> dir(mtrand)
['__builtins__', '__doc__', '__file__', '__name__', '__package__']
这种行为怎么可能?
编辑:
- 这两个测试在不同的python进程中执行。
- 弄乱系统路径是愚蠢的,我知道这一点。但这不是针对普通程序,而是用于自动完成。我当然不想导入整个 numpy 包。我只是想能够做一个
dir(mtrand)
尝试导入扩展模块(即从共享库加载的模块)两次会导致未定义的行为。 引用reload()
的文档:
但是,在许多情况下,扩展模块并非设计为多次初始化,并且在重新加载时可能会以任意方式失败。
顺便说一句,这恰好适用于我的numpy
安装:
>>> from numpy.random import mtrand
>>> dir(mtrand)
['RandomState', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__test__', '_rand', 'beta', 'binomial', 'bytes', 'chisquare', 'dirichlet', 'exponential', 'f', 'gamma', 'geometric', 'get_state', 'gumbel', 'hypergeometric', 'laplace', 'logistic', 'lognormal', 'logseries', 'multinomial', 'multivariate_normal', 'negative_binomial', 'noncentral_chisquare', 'noncentral_f', 'normal', 'np', 'pareto', 'permutation', 'poisson', 'power', 'rand', 'randint', 'randn', 'random_integers', 'random_sample', 'rayleigh', 'seed', 'set_state', 'shuffle', 'standard_cauchy', 'standard_exponential', 'standard_gamma', 'standard_normal', 'standard_t', 'triangular', 'uniform', 'vonmises', 'wald', 'weibull', 'zipf']
>>> sys.path.append("/usr/lib/pyshared/python2.7/numpy/random")
>>> import mtrand
>>> dir(mtrand)
['RandomState', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__test__', '_rand', 'beta', 'binomial', 'bytes', 'chisquare', 'dirichlet', 'exponential', 'f', 'gamma', 'geometric', 'get_state', 'gumbel', 'hypergeometric', 'laplace', 'logistic', 'lognormal', 'logseries', 'multinomial', 'multivariate_normal', 'negative_binomial', 'noncentral_chisquare', 'noncentral_f', 'normal', 'np', 'pareto', 'permutation', 'poisson', 'power', 'rand', 'randint', 'randn', 'random_integers', 'random_sample', 'rayleigh', 'seed', 'set_state', 'shuffle', 'standard_cauchy', 'standard_exponential', 'standard_gamma', 'standard_normal', 'standard_t', 'triangular', 'uniform', 'vonmises', 'wald', 'weibull', 'zipf']
这是未定义的行为,所以任何事情都可能发生。
不知道为什么有人为此给你打-1。 在遇到自己的Python导入问题之后,我的信念是,当您弄乱sys.path
时,您已经绕过了通常会执行的init.py文件。 /usr/lib/pymodules/python2.7/numpy
和/usr/lib/pymodules/python2.7/numpy/random
(可能)是python包,包含init.py文件。 默认情况下,每当导入该包或子包中的任何内容时,都会包含 init 文件。 通过将路径指向文件树的更深层次,您绕过了这些 init 文件,从而改变了包的预期行为。
还有来自斯文的好信息。 我假设您的 2 个导入不在同一个正在运行的 Python 实例中。如果是,那么斯文的答案是相关的。
正如Endophage指出的那样,玩sys.path
确实是愚蠢的。但我想我开始了它,因为我不想执行任何 Python 代码,这对于自动完成来说会很酷。我不认为这对c_builtin模块来说是一个大问题。但是,有些模块确实需要正确的包路径(请参阅下面关于段错误的注释)。
我什至为PyQt4
做了一个解决方法,但注意到这不是唯一的解决方法:
sys.path.append('/usr/lib/python2.7/dist-packages/PyQt4')
try:
import QtCore
except SystemError:
QtCore = sys.modules['PyQt4.QtCore']
debug.warning('Loaded a module with SystemError.')
这包括捕获SystemError
,然后从 sys.modules 使用它。事实上,这是非常愚蠢的,因为我不知道这种操作的任何副作用。当我测试PySide
(这是另一个Qt包装器)时,在某些情况下会发生段错误。
所以我想出了更pythonic的解决方案来再次加载这样的模块:from PyQt4 import QtCore
和from numpy.random import random
。
有趣的是,加载这些模块及其完整路径的内存占用量与弄乱sys.path
一样多。