Python 导入内部差异



我以两种不同的方式导入了一个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 QtCorefrom numpy.random import random

有趣的是,加载这些模块及其完整路径的内存占用量与弄乱sys.path一样多。

相关内容

  • 没有找到相关文章

最新更新