오래 실행되는 Python 서버가 있으며 서버를 다시 시작하지 않고 서비스를 업그레이드하고 싶습니다. 가장 좋은 방법은 무엇입니까?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
오래 실행되는 Python 서버가 있으며 서버를 다시 시작하지 않고 서비스를 업그레이드하고 싶습니다. 가장 좋은 방법은 무엇입니까?
if foo.py has changed:
unimport foo <-- How do I do this?
import foo
myfoo = foo.Foo()
답변:
reload
내장 함수 를 사용하여 이미 가져온 모듈을 다시로드 할 수 있습니다 (Python 3.4+ 만 해당) .
from importlib import reload
import foo
while True:
# Do some things.
if is_changed(foo):
foo = reload(foo)
파이썬 3에서는 모듈 reload
로 옮겨졌습니다 imp
. 3.4에서는 imp
찬성이 사용됩니다 importlib
, 그리고 reload
후자에 추가되었습니다. 3 이상을 대상으로하는 경우 호출 reload
하거나 가져올 때 적절한 모듈을 참조하십시오 .
나는 이것이 당신이 원하는 것이라고 생각합니다. Django의 개발 서버와 같은 웹 서버는이를 사용하여 서버 프로세스 자체를 다시 시작하지 않고도 코드 변경의 영향을 볼 수 있습니다.
문서에서 인용하려면 :
파이썬 모듈의 코드가 다시 컴파일되고 모듈 수준 코드가 다시 실행되어 모듈 사전의 이름에 바인딩되는 새로운 객체 집합을 정의합니다. 확장 모듈의 초기화 기능은 두 번째로 호출되지 않습니다. 파이썬의 다른 모든 객체와 마찬가지로 이전 객체는 참조 횟수가 0으로 떨어진 후에 만 재생됩니다. 모듈 네임 스페이스의 이름은 새로운 객체 또는 변경된 객체를 가리 키도록 업데이트됩니다. 이전 개체에 대한 다른 참조 (예 : 모듈 외부의 이름)는 새 개체를 참조하기 위해 리 바인드되지 않으며 원하는 경우 각 네임 스페이스에서 업데이트되어야합니다.
질문에서 언급했듯이 클래스가 모듈 에 Foo
있으면 객체 를 재구성 Foo
해야 foo
합니다.
X
모듈이 아닌 경우 다음을 수행 할 수 있습니다.import sys; reload(sys.modules[X.__module__])
is_changed
함수는 여러분이 작성해야 할 임의의 함수일 것입니다. 내장되어 있지 않습니다. 예를 들어, 가져 오는 모듈에 해당하는 파일을 열고 캐시 된 버전으로 비교하여 변경되었는지 확인할 수 있습니다.
Python 3.0–3.3에서는 다음을 사용합니다. imp.reload(module)
그러나 @Stefan 덕분 imp
에 3.4에서 더 이상 사용되지 않습니다 importlib
. ).
나는 생각한다 그러므로 당신이 지금 사용하는 거라고, importlib.reload(module)
잘 모르겠어요하지만,.
reload(__builtins__)
2.X에서 유효
순수한 파이썬이 아닌 경우 모듈을 삭제하는 것이 특히 어려울 수 있습니다.
가져온 정보는 어떻게 삭제합니까?
sys.getrefcount ()를 사용하여 실제 참조 수를 찾을 수 있습니다.
>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3
3보다 큰 숫자는 모듈을 제거하기 어렵다는 것을 나타냅니다. 자체 개발 한 "빈"(아무것도 포함) 모듈은 다음에 가비지 수집되어야합니다.
>>> del sys.modules["empty"]
>>> del empty
세 번째 참조는 getrefcount () 함수의 아티팩트이므로
setattr(package, "empty", None)
reload()
최상위 모듈 만 다시로드하며 sys.modules에서 먼저 삭제하지 않으면 내부의 모든 항목이 다시로드되지 않습니다.
reload(module)
그러나 완전히 독립형 인 경우에만 가능합니다. 다른 것이 모듈 (또는 모듈에 속하는 객체)에 대한 참조가 있으면 이전 코드가 예상보다 오래 걸려서 미묘하고 호기심 많은 오류가 발생합니다.isinstance
합니다. 같은 코드.
단방향 종속성이있는 경우 이전 코드에 대한 모든 참조를 제거하려면 다시로드 된 모듈에 종속 된 모든 모듈을 다시로드해야합니다. 그런 다음 재로드 된 모듈에 의존하는 모듈을 재귀 적으로 다시로드하십시오.
예를 들어 패키지 재로드를 처리 할 때 매우 일반적인 순환 종속성이있는 경우 그룹의 모든 모듈을 한 번에 언로드해야합니다. 당신은 이것을 할 수 없습니다reload()
종속성을 새로 고치기 전에 각 모듈을 다시 가져 와서 이전 참조가 새 모듈로 들어올 수 있기 때문에이 .
이 경우이를 수행하는 유일한 방법은 해킹 sys.modules
하는 것입니다. sys.modules
다음 가져올 때 다시로드 할 각 항목을 살펴보고 삭제 None
해야하며 실패한 상대 가져 오기 캐싱과 관련된 구현 문제를 처리 해야하는 값을 가진 항목도 삭제해야합니다 . 별로 좋지는 않지만 코드베이스 외부에 참조를 남기지 않는 완전히 독립적 인 종속성 세트가있는 한 실행 가능합니다.
서버를 다시 시작하는 것이 가장 좋습니다. :-)
None
이 문제가 정확히 발생하기 때문에 값으로 부품을 정교하게 할 수 있습니까? sys.modules
다시 가져 오기 한 후 항목을 삭제 하고 있습니다 None
. 가져온 일부 종속성은 입니다.
None
'실제'항목이 삭제되었을 때 항목이 가져 오기 메커니즘을 통해 어떻게 되돌아 오는지 잘 알지 못합니다 (import.c 코드를 보더라도) . 내재적 상대적 수입이 사라지면서 미래에는 더 이상 문제가되지 않습니다. 그 동안 None
가치가있는 모든 항목을 삭제 하면 문제가 해결되는 것으로 보입니다.
reload
기능 을 의미 합니까? 내장되어 있으므로 라이브러리를 가져올 필요가 없습니다.
if 'myModule' in sys.modules:
del sys.modules["myModule"]
nose.run()
후에도reload(my_module)
%run my_module
[del(sys.modules[mod] for mod in sys.modules.keys() if mod.startswith('myModule.')]
.
import sys; import json; del sys.modules['json']; print(json.dumps([1]))
json 모듈이 더 이상 sys.modules에 없어도 여전히 작동합니다.
Python 2의 경우 내장 함수 reload ()를 사용하십시오 .
reload(module)
Python 2 및 3.2–3.3의 경우 모듈 imp에서 다시로드를 사용하십시오 .
import imp
imp.reload(module)
그러나 importlib에 찬성하여 버전 3.4부터 imp
더 이상 사용되지 않으므로 다음을 사용하십시오.
import importlib
importlib.reload(module)
또는
from importlib import reload
reload(module)
from six import reload_module
( pip install six
물론 첫 번째 필요 )
허용 된 답변은 from from X import Y 사례를 처리하지 않습니다. 이 코드는 코드와 표준 가져 오기 사례도 처리합니다.
def importOrReload(module_name, *names):
import sys
if module_name in sys.modules:
reload(sys.modules[module_name])
else:
__import__(module_name, fromlist=names)
for name in names:
globals()[name] = getattr(sys.modules[module_name], name)
# use instead of: from dfly_parser import parseMessages
importOrReload("dfly_parser", "parseMessages")
리로딩의 경우 최상위 레벨 이름을 새로 리로드 된 모듈에 저장된 값으로 다시 할당하여 업데이트합니다.
>>> from X import Y
>>> __import__('X', fromlist='Y')
fromlist='*'
있습니까?
from
수입 명세서에서 거의 모든 사용을 중단하는 경향이 있습니다. 그냥 스탁 import <package>
및 코드에서 명시 적 package.symbol. 이것이 항상 가능하거나 바람직하지는 않다는 것을 인식하십시오. (한가지 예외가 있습니다 : 향후 import print_function에서)
foo = reload(foo); from foo import *
이것은 모듈을 다시로드하는 현대적인 방법입니다.
from importlib import reload
3.5 이전의 Python 버전을 지원하려면 다음을 시도하십시오.
from sys import version_info
if version_info[0] < 3:
pass # Python 2 has built in reload
elif version_info[0] == 3 and version_info[1] <= 4:
from imp import reload # Python 3.0 - 3.4
else:
from importlib import reload # Python 3.5+
사용하려면 다시로드하려는 모듈로 reload(MODULE)
교체 MODULE
하십시오.
예를 들어, 모듈 reload(math)
을 다시로드합니다 math
.
from importlib import reload
. 그럼 당신은 할 수 있습니다 reload(MODULE_NAME)
. 이 기능이 필요하지 않습니다.
modulereload(MODULE_NAME)
단순한 것보다 더 설명이 필요 reload(MODULE_NAME)
하고 다른 기능과 충돌 할 가능성이 낮다고 생각합니다.
당신이 경우에 없는 서버에 있지만 개발 과 자주 모듈을 다시로드해야, 여기에 좋은 팁입니다.
먼저 Jupyter Notebook 프로젝트에서 우수한 IPython 셸을 사용하고 있는지 확인하십시오 . Jupyter를 설치 한 후에는 ipython
, 또는 jupyter console
, 또는 더 나은으로 시작할 수 있으며 jupyter qtconsole
, 이는 모든 OS에서 코드 완성이 가능한 멋진 색상의 콘솔을 제공합니다.
이제 쉘에 다음을 입력하십시오.
%load_ext autoreload
%autoreload 2
이제 스크립트를 실행할 때마다 모듈이 다시로드됩니다.
를 넘어서서 자동 재로드 마법의2
다른 옵션이 있습니다 :
%autoreload
Reload all modules (except those excluded by %aimport) automatically now.
%autoreload 0
Disable automatic reloading.
%autoreload 1
Reload all modules imported with %aimport every time before executing the Python code typed.
%autoreload 2
Reload all modules (except those excluded by %aimport) every time before
executing the Python code typed.
나와 같은 사람들은 모든 모듈을 언로드하고 싶어합니다 ( Emacs 의 Python 인터프리터에서 실행할 때 ).
for mod in sys.modules.values():
reload(mod)
자세한 정보는 Python 모듈 다시로드에 있습니다.
sys.modules.values()
모듈이 아니기 때문에 (2.6에서) 안정적으로 작동하지 않는 것 같습니다 . 예를 들면 다음과 같습니다. >>> type (sys.modules.values () [1]) <class 'email.LazyImporter'> 따라서 해당 코드를 실행하려고하면 코드가 넘어갑니다 (실제 해결책이 아니라는 것을 알고 있습니다. 지적).
if mod and mod.__name__ != "__main__": imp.reload(mod)
Enthought Traits에는이를 위해 상당히 잘 작동하는 모듈이 있습니다. https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html
변경된 모듈을 다시로드하고이를 사용하는 다른 모듈 및 인스턴스화 된 객체를 업데이트합니다. 대부분의 경우 __very_private__
메서드 와 함께 작동하지 않으며 클래스 상속을 막을 수는 있지만 PyQt GUI를 작성할 때 호스트 응용 프로그램을 다시 시작하거나 Maya 또는 Nuke와 같은 프로그램 내에서 실행되는 항목을 다시 시작 해야하는 시간을 크게 절약합니다. 아마도 20-30 %의 시간 동안 작동하지는 않지만 여전히 굉장히 도움이됩니다.
Enthought의 패키지는 파일이 변경되는 순간에 파일을 다시로드하지 않습니다. 명시 적으로 호출해야하지만 실제로 필요한 경우 구현하기가 쉽지는 않습니다.
2018-02-01
foo
을 미리 가져와야합니다. from importlib import reload
, reload(foo)
다른 옵션. 파이썬 기본값 importlib.reload
은 인수로 전달 된 라이브러리를 다시 가져옵니다. 그것은 하지 않습니다 당신의 lib 디렉토리 가져 오기 그 라이브러리를 다시로드합니다. 많은 파일을 변경하고 가져 오기 위해 다소 복잡한 패키지가있는 경우에는 다시로드 해야합니다. .
당신이있는 경우 IPython 또는 Jupyter가 설치되어, 당신은 깊은 재 장전 모든 libs와에 대한 기능을 사용할 수 있습니다 :
from IPython.lib.deepreload import reload as dreload
dreload(foo)
Jupyter가없는 경우 쉘에 다음 명령으로 설치하십시오.
pip3 install jupyter
reload() argument must be module
. 사용자 정의 함수 가져 오기를 사용하고 있으며 작동하지 않는 것 같습니다. 내장 모듈을 사용하면 작동합니다. :-((제 코드에 작은 변화를 줄 때마다 iPython을 새로 고침하는 데 시간 낭비입니다.
이전의 해결책은 재설정 정보를 얻는 데 유용하지만 모든 참조를 변경하지는 않습니다 ( reload
필요한 것 이상 ). 실제로 모든 참조를 설정하려면 가비지 수집기로 가서 참조를 다시 작성해야했습니다. 이제는 매력처럼 작동합니다!
참고이 하지 않습니다 GC가 꺼져, 또는 경우 작업 GC 모니터링 아니에요 데이터를 다시로드하는 경우. GC를 망치고 싶지 않다면 원래의 대답으로 충분할 수 있습니다.
새로운 코드 :
import importlib
import inspect
import gc
from weakref import ref
def reset_module(module, inner_modules_also=True):
"""
This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
to be the reloaded-module's
:param module: The module to reload (module reference, not the name)
:param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
"""
# For the case when the module is actually a package
if inner_modules_also:
submods = {submod for _, submod in inspect.getmembers(module)
if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
for submod in submods:
reset_module(submod, True)
# First, log all the references before reloading (because some references may be changed by the reload operation).
module_tree = _get_tree_references_to_reset_recursively(module, module.__name__)
new_module = importlib.reload(module)
_reset_item_recursively(module, module_tree, new_module)
def _update_referrers(item, new_item):
refs = gc.get_referrers(item)
weak_ref_item = ref(item)
for coll in refs:
if type(coll) == dict:
enumerator = coll.keys()
elif type(coll) == list:
enumerator = range(len(coll))
else:
continue
for key in enumerator:
if weak_ref_item() is None:
# No refs are left in the GC
return
if coll[key] is weak_ref_item():
coll[key] = new_item
def _get_tree_references_to_reset_recursively(item, module_name, grayed_out_item_ids = None):
if grayed_out_item_ids is None:
grayed_out_item_ids = set()
item_tree = dict()
attr_names = set(dir(item)) - _readonly_attrs
for sub_item_name in attr_names:
sub_item = getattr(item, sub_item_name)
item_tree[sub_item_name] = [sub_item, None]
try:
# Will work for classes and functions defined in that module.
mod_name = sub_item.__module__
except AttributeError:
mod_name = None
# If this item was defined within this module, deep-reset
if (mod_name is None) or (mod_name != module_name) or (id(sub_item) in grayed_out_item_ids) \
or isinstance(sub_item, EnumMeta):
continue
grayed_out_item_ids.add(id(sub_item))
item_tree[sub_item_name][1] = \
_get_tree_references_to_reset_recursively(sub_item, module_name, grayed_out_item_ids)
return item_tree
def _reset_item_recursively(item, item_subtree, new_item):
# Set children first so we don't lose the current references.
if item_subtree is not None:
for sub_item_name, (sub_item, sub_item_tree) in item_subtree.items():
try:
new_sub_item = getattr(new_item, sub_item_name)
except AttributeError:
# The item doesn't exist in the reloaded module. Ignore.
continue
try:
# Set the item
_reset_item_recursively(sub_item, sub_item_tree, new_sub_item)
except Exception as ex:
pass
_update_referrers(item, new_item)
@bobince의 답변에 작성된 것처럼 다른 모듈에 해당 모듈에 대한 참조가 이미있는 경우 (특히 as
같은 키워드 로 가져온 경우 import numpy as np
) 해당 인스턴스를 덮어 쓰지 않습니다.
이는 구성 모듈의 "클린 슬레이트"상태가 필요한 테스트를 적용 할 때 매우 문제가되었으므로 ' 함수 reset_module
를 사용 하고 선언 된 모든 모듈 속성을 재귀 적으로 덮어 쓰는 함수 를 작성했습니다 . Python 버전 3.6으로 테스트되었습니다.importlib
reload
import importlib
import inspect
from enum import EnumMeta
_readonly_attrs = {'__annotations__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__',
'__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__func__', '__ge__', '__get__',
'__getattribute__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__',
'__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__',
'__reduce__', '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', '__weakref__', '__members__', '__mro__', '__itemsize__', '__isabstractmethod__',
'__basicsize__', '__base__'}
def reset_module(module, inner_modules_also=True):
"""
This function is a stronger form of importlib's `reload` function. What it does, is that aside from reloading a
module, it goes to the old instance of the module, and sets all the (not read-only) attributes, functions and classes
to be the reloaded-module's
:param module: The module to reload (module reference, not the name)
:param inner_modules_also: Whether to treat ths module as a package as well, and reload all the modules within it.
"""
new_module = importlib.reload(module)
reset_items = set()
# For the case when the module is actually a package
if inner_modules_also:
submods = {submod for _, submod in inspect.getmembers(module)
if (type(submod).__name__ == 'module') and (submod.__package__.startswith(module.__name__))}
for submod in submods:
reset_module(submod, True)
_reset_item_recursively(module, new_module, module.__name__, reset_items)
def _reset_item_recursively(item, new_item, module_name, reset_items=None):
if reset_items is None:
reset_items = set()
attr_names = set(dir(item)) - _readonly_attrs
for sitem_name in attr_names:
sitem = getattr(item, sitem_name)
new_sitem = getattr(new_item, sitem_name)
try:
# Set the item
setattr(item, sitem_name, new_sitem)
try:
# Will work for classes and functions defined in that module.
mod_name = sitem.__module__
except AttributeError:
mod_name = None
# If this item was defined within this module, deep-reset
if (mod_name is None) or (mod_name != module_name) or (id(sitem) in reset_items) \
or isinstance(sitem, EnumMeta): # Deal with enums
continue
reset_items.add(id(sitem))
_reset_item_recursively(sitem, new_sitem, module_name, reset_items)
except Exception as ex:
raise Exception(sitem_name) from ex
참고 : 조심해서 사용하십시오! 주변 장치가 아닌 모듈 (예 : 외부에서 사용하는 클래스를 정의하는 모듈)에서이 기능을 사용하면 Python의 내부 문제 (예 : 산세 / 비산 세 문제)가 발생할 수 있습니다.
Abaqus의 경우 나를 위해 그것이 작동하는 방식입니다. 파일이 Class_VerticesEdges.py라고 상상해보십시오
sys.path.append('D:\...\My Pythons')
if 'Class_VerticesEdges' in sys.modules:
del sys.modules['Class_VerticesEdges']
print 'old module Class_VerticesEdges deleted'
from Class_VerticesEdges import *
reload(sys.modules['Class_VerticesEdges'])
Sublime Text 내부에 무언가를 다시로드하려고하는 데 많은 어려움이 있었지만 마침내 모듈을 다시로드하는 sublime_plugin.py
데 사용 하는 코드를 기반으로 Sublime Text에서 모듈을 다시로드하기 위해이 유틸리티를 작성할 수있었습니다 .
아래는 이름에 공백이있는 경로에서 모듈을 다시로드 할 수있게 한 다음 나중에 다시로드 한 후에 평소와 같이 가져올 수 있습니다.
def reload_module(full_module_name):
"""
Assuming the folder `full_module_name` is a folder inside some
folder on the python sys.path, for example, sys.path as `C:/`, and
you are inside the folder `C:/Path With Spaces` on the file
`C:/Path With Spaces/main.py` and want to re-import some files on
the folder `C:/Path With Spaces/tests`
@param full_module_name the relative full path to the module file
you want to reload from a folder on the
python `sys.path`
"""
import imp
import sys
import importlib
if full_module_name in sys.modules:
module_object = sys.modules[full_module_name]
module_object = imp.reload( module_object )
else:
importlib.import_module( full_module_name )
def run_tests():
print( "\n\n" )
reload_module( "Path With Spaces.tests.semantic_linefeed_unit_tests" )
reload_module( "Path With Spaces.tests.semantic_linefeed_manual_tests" )
from .tests import semantic_linefeed_unit_tests
from .tests import semantic_linefeed_manual_tests
semantic_linefeed_unit_tests.run_unit_tests()
semantic_linefeed_manual_tests.run_manual_tests()
if __name__ == "__main__":
run_tests()
처음으로 실행하면 모듈이로드되지만 나중에 메소드 / 기능을 다시 사용할 수 있으면 run_tests()
테스트 파일이 다시로드됩니다. Sublime Text ( Python 3.3.6
)를 사용하면 인터프리터가 닫히지 않기 때문에 많은 일이 발생합니다 (Sublime Text, 즉 Python3.3
인터프리터 를 다시 시작하지 않는 한 ).
다른 방법은 함수에서 모듈을 가져 오는 것입니다. 이렇게하면 함수가 완료되면 모듈이 가비지 수집됩니다.
sys.modules
.