Я пытаюсь найти причину ошибки: 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. Я хотел бы знать, связано ли это с тем, что:
Кажется, трудно понять, потому что, если вызывается перезагрузка, переменные, назначенные пространству имен модулей, выживают при перезагрузке, за исключением случаев, когда они повторно инициализируются самим модулем:
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()
Несмотря на то, что некоторые версии 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.
sys.api_version
.