Можно узнать, был ли модуль Python перезагружен?

1

Я пытаюсь найти причину ошибки: 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 было переназначено

Кажется, трудно понять, потому что, если вызывается перезагрузка, переменные, назначенные пространству имен модулей, выживают при перезагрузке, за исключением случаев, когда они повторно инициализируются самим модулем:

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 ответ

2
Лучший ответ

Несмотря на то, что некоторые версии Python 2 очень сильно нахмурились, он перезагружает sys для восстановления функции sys.setdefaultencoding(). Это почти всегда является причиной этой проблемы.

Таким образом, вы можете обнаружить, что sys был перезагружен, проверяя атрибут setdefaultencoding:

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

Это будет работать только на Python 2. Или вы можете увеличить последовательность sys.flags struct с дополнительным полем:

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 и методы, которые нужно разблокировать, а также работает на Python 3.

Вы можете предотвратить перезагрузку sys путем упаковки __builtin__.reload importlib.reload/imp.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 или какой-либо другой механизм для записи или создания шума о том, что sys перезагружается; вы, вероятно, хотите включить вызывающего абонента в такие предупреждения.

Выполните вышеуказанный модуль как можно раньше, чтобы убедиться, что вы можете поймать код, который это делает, возможно, вставив его в модуль sitecustomize или sitecustomize его из .pth файла, установленного в каталог site-packages. Любая строка в файле .pth которая начинается с import, выполняется как код Python модулем site.py при запуске Python, поэтому следующее содержимое в таком файле:

import yourpackage.sysreload_neutraliser

введет импорт во время запуска Python.

  • 0
    Спасибо - это довольно комплексное решение, которое удобно для предотвращения перезагрузки (почему полезно). Для людей, которые приходят сюда, просто посмотрите, не была ли sys перезагружена, назначьте sys.api_version и попробуйте проверить, не возвращается ли он назад, более простым способом,
  • 0
    @ user48956: другой код все еще может полагаться на sys.api_version .
Показать ещё 4 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню