【问题标题】:Python import internals differencePython导入内部差异
【发布时间】:2012-04-16 22:43:17
【问题描述】:

我以两种不同的方式导入了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)

【问题讨论】:

  • 这让我觉得自动完成的错误方法。 (Always include your actual aims in the question right from the beginning.) 你不能在不导入 NumPy 的情况下导入 mtrand - 对我来说,你的第二种方法也“有效”,但就像正常导入一样,将所有 NumPy 绘制到 sys.modules 中。
  • 与其自己编写代码,不如查看标准库中的rlcompleter、此模块的IPython's enhanced versionrope's 自动补全。后者是最先进的。
  • rlcompleter 和 IPython 非常简单。 Rope 是唯一真正的自动补全。但这对我从来没有用过——所以我决定做一些更好的事情(所有其他解决方案都是简单的 -> python-omnicomplete,或者不是免费的 -> pycharm)。它已经工作得很好,但内置函数仍然是个问题,因为它们无法被评估。

标签: python import numpy imp


【解决方案1】:

尝试导入扩展模块(即从共享库加载的模块)两次会导致未定义的行为。引用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']

这是未定义的行为,所以任何事情都可能发生。

【讨论】:

  • 这可能是一个很好的提示,但我在不同的 python 实例中导入了它们。 -> 所以这不是问题。
  • 在不同的过程中尝试,效果将是我描述的那个(我猜上面的情况是你描述的未定义行为)
【解决方案2】:

不知道为什么有人为此给了你一个-1。在遇到我自己的 Python 导入问题后,我相信当你弄乱sys.path 时,你已经绕过了通常会执行的 init.py 文件。 /usr/lib/pymodules/python2.7/numpy/usr/lib/pymodules/python2.7/numpy/random (可能)是 python 包并包含 init.py 文件。每当导入该包或子包中的任何内容时,都会默认包含初始化文件。通过将路径指向文件树的更深层次,您绕过了这些初始化文件,从而改变了包的预期行为。

还有来自 Sven 的好消息。我假设您的 2 个导入不在 Python 的同一个运行实例中。如果是,那么 Sven 的回答就是相关的。

【讨论】:

  • 搞乱 sys 路径确实很愚蠢 - 通常情况下。但是因为我正在写一个自动补全,那真的是另一回事。我当然不想导入整个numpy 库。只是模块,在它上面做一个dir(mtrand)(在exec中)。
【解决方案3】:

正如 Endophage 指出的那样,玩sys.path 确实很愚蠢。但我想我开始了它,因为我不想执行任何 Python 代码,这对于自动完成来说非常酷。我不认为这对于 c_builtin 模块来说是个大问题。但是,有些模块确实需要正确的包路径(请参阅下面关于 segfaults 的评论)。

我什至为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 一样多。

【讨论】:

    猜你喜欢
    • 2013-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-09-08
    • 2019-11-22
    相关资源
    最近更新 更多