可以知道是否已重新加载python模块?

时间:2018-06-15 17:18:25

标签: python

我正在尝试追踪错误的原因:https://github.com/numba/numba/issues/3027

似乎(对于一些numba用户,但不是全部用户)

import sys
import numba

@numba.njit
def some_func(begin1, end1, begin2, end2):
  if begin1 > begin2: return some_func(begin2, end2, begin1, end1)
  return end1 + 1 >= begin2

sys.stdout = sys.stderr
x = id(sys.stdout)
some_func(0,1,2,3)
y = id(sys.stdout)
assert x==y # Fail

sys.stdout的值在调用somefunc之前和之后不同。我想知道这是否是因为:

  • reload(sys)被调用,或
  • sys.stdout已重新分配

似乎很难知道,因为如果调用reload,分配给模块命名空间的变量在重新加载后仍然存在,除非它们被模块本身重新初始化:

import sys
sys.stdout = None
sys.zzz = 123
sys = reload(sys)
sys.stderr.write("sys.stdout = {}\n".format(sys.stdout)) # Reset to file object
sys.stderr.write("sys.zzz = {}\n".format(sys.zzz)) # Surprise success!
sys.stderr.flush()

1 个答案:

答案 0 :(得分:2)

虽然非常不满,some Python 2 code reloads sys to restore the sys.setdefaultencoding() function。这几乎总是造成这个问题的原因。

因此,您可以通过检查sys属性来检测setdefaultencoding已重新加载:

if hasattr(sys, 'setdefaultencoding'):
    # sys was reloaded!

这只适用于Python 2.或者您可以使用额外字段扩充sys.flags struct sequence

from collections import namedtuple
import sys, re

_sys_flags_fields = re.findall('(\w+)=\d', repr(sys.flags))
_sys_flags_augmented = namedtuple('flags', _sys_flags_fields + ['sys_not_reloaded'])
sys.flags = _sys_flags_augmented(*sys.flags + (1,))

之后你可以测试:

if not getattr(sys.flags, 'sys_not_reloaded', 0):

扩充sys.flags比大多数其他sys操作更安全,因为第三方代码可能依赖于已记录的sys属性和方法,而和< / em>它也可以在Python 3上运行。

您可以通过打包sys / __builtin__.reload / importlib.reload阻止 imp.reload重新加载:

try:
    # Python 2
    import __builtin__ as targetmodule
except ImportError:
    # Python 3.4 and up
    try:
        import importlib as targetmodule
        targetmodule.reload   # NameError for older Python 3 releases
    except (ImportError, AttributeError):
        # Python 3.0 - 3.3
        import imp as targetmodule

from functools import wraps

def reload_wrapper(f):
    @wraps(f)
    def wrapper(module):
        if getattr(module, '__name__', None) == 'sys':
            raise ValueError('sys should never be reloaded!')
        return f(module)
    return wrapper

targetmodule.reload = reload_wrapper(targetmodule.reload)

您可以使用warnings module或其他一些机制来记录或警告sys正在重新加载的事实,而不是引发异常;你可能希望include the caller加入这样的警告。

尽早执行上述模块,以确保可以通过将其插入sitecustomize模块或从.pth文件中触发来捕获执行此操作的代码安装到site-packages目录中。 .pth文件中以import开头的任何行都是executed as Python code by the site.py module at Python startup,因此此类文件中包含以下内容:

import yourpackage.sysreload_neutraliser

会在Python启动时注入导入。