代码之家  ›  专栏  ›  技术社区  ›  user48956

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

  •  1
  • user48956  · 技术社区  · 7 年前

    我想找出一个错误的原因: 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
    

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

    • 调用了重新加载(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 回复  |  直到 7 年前
        1
  •  2
  •   Martijn Pieters    7 年前

    虽然很不高兴, some Python 2 code reloads sys to restore the sys.setdefaultencoding() function . 这几乎总是这个问题的原因。

    所以你可以察觉到 系统 通过检查 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):
    

    增广 小精灵 比其他的都安全 系统 操作,因为第三方代码可能依赖于 系统 不受限制的属性和方法, 它也适用于python 3。

    你可以 防止 系统 通过包装重新装载 __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 或其他机制来记录或制造噪音 系统 正在重新加载;您可能希望 include the caller 变成这样的警告。

    尽可能早地执行上面的模块,以确保您可以捕获正在执行此操作的代码,方法可能是将其插入 sitecustomize 模块,或通过从 .pth 文件安装到 site-packages 目录。任何一行 甲状旁腺激素 以开头的文件 import executed as Python code by the site.py module at Python startup ,因此该文件中包含以下内容:

    import yourpackage.sysreload_neutraliser
    

    将在python启动时注入导入。