programing

Python 모듈을 언로드(새로고침)하려면 어떻게 해야 합니까?

projobs 2022. 9. 25. 11:04
반응형

Python 모듈을 언로드(새로고침)하려면 어떻게 해야 합니까?

Python 서버를 오래 사용하고 있기 때문에, 서버를 재기동하지 않고 서비스를 업그레이드할 수 있으면 좋겠습니다.어떻게 하면 좋을까요?

if foo.py has changed:
    unimport foo  <-- How do I do this?
    import foo
    myfoo = foo.Foo()

모듈을 이미 Import한 경우 를 사용하여 모듈을 새로고침할 수 있습니다.

from importlib import reload  # Python 3.4+
import foo

while True:
    # Do some things.
    if is_changed(foo):
        foo = reload(foo)

Python 2에는 이 내장되어 있습니다.Python 3에서는 모듈로 이동되었습니다.3.4에서는imp를 위해 권장되지 않습니다.3 이후를 타겟으로 할 경우 콜 시 해당 모듈을 참조해 주십시오.reload수입하다

이게 네가 원하는 거라고 생각해.Django의 개발 서버와 같은 웹 서버는 이를 사용하여 서버 프로세스를 재시작하지 않고도 코드 변경의 효과를 볼 수 있습니다.

문서에서 인용하려면:

  • Python 모듈의 코드가 다시 컴파일되고 모듈 수준 코드가 다시 실행되며, 모듈을 처음 로드한 로더를 다시 사용하여 모듈 사전의 이름에 바인딩되는 새로운 개체 집합을 정의합니다.init확장 모듈의 기능은 두 번째 호출되지 않습니다.
  • Python의 다른 모든 객체와 마찬가지로 오래된 객체는 참조 수가 0으로 떨어진 후에만 회수됩니다.
  • 모듈 네임스페이스의 이름이 새로 생성되거나 변경된 개체를 가리키도록 업데이트됩니다.
  • 오래된 오브젝트에 대한 기타 참조(모듈 외부 이름 등)는 새로운 오브젝트를 참조하기 위해 리바운드되지 않으며 필요에 따라 오브젝트가 발생하는 각 네임스페이스에서 갱신해야 합니다.

아까에서 지적하신 처럼 다시 해 봐야 합니다.Foo:Foo는 클클 the에 있습니다.foo★★★★★★ 。

Python 3.0~3.3에서는 다음을 사용합니다.

BDFL은 이 질문에 답했습니다.

단, 3.4에서는 (고맙습니다@Stefan!) 위해 폐지되었습니다.

그래서 지금 사용하시는 게 좋을 것 같습니다만, 잘 모르겠습니다.

순수 Python이 아니면 모듈을 삭제하는 것이 특히 어려울 수 있습니다.

다음은 다음 정보입니다.Import된 모듈을 삭제하려면 어떻게 해야 하나요?

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() 함수의 아티팩트입니다.

reload(module)완전히 독립형일 경우에만 사용할 수 있습니다.)에 보다 오래 또, 「」(이러한 에러)나, 「」(이러한 에러)가 발생합니다.isinstance같은 코드의 다른 버전에서는 동작하지 않습니다.

단방향 의존관계가 있는 경우 새로고침된 모듈에 의존하는 모든 모듈을 새로고침하여 오래된 코드에 대한 참조를 모두 삭제해야 합니다.새로고침된 모듈에 의존하는 모듈을 재귀적으로 새로고침합니다.

패키지 새로고침을 처리할 때 등 순환 의존 관계가 있는 경우 그룹 내의 모든 모듈을 한 번에 언로드해야 합니다.안 요.reload()의존관계가 갱신되기 전에 각 모듈을 다시 Import하여 오래된 참조를 새로운 모듈에 슬금슬금 삽입할 수 있도록 하기 때문입니다.

입니다.sys.modules지원 대상이 아닙니다. 과정을 거쳐서 sys.modules 시 이 Import하다, Import하다, Import하다, Import하다, Import하다의 엔트리를 합니다.None실패한 상대 Import 캐싱과 관련된 구현 문제를 처리합니다.그다지 좋은 것은 아니지만, 코드 베이스 밖에 레퍼런스를 남기지 않는 완전한 의존 관계가 있는 한, 동작할 수 있습니다.

서버를 재기동하는 것이 가장 좋습니다. :- )

Python 2의 경우 내장 함수를 사용합니다.

reload(module)

Python 2Python 3.2경우: module imp:

import imp
imp.reload(module)

Python 3 3.4의 경우,imp 는 에 의해 권장되지 않으므로 다음 명령을 사용합니다.

import importlib
importlib.reload(module)

또는 다음과 같이 입력합니다.

from importlib import reload
reload(module)

TL;DR:

© Python © 3.4:importlib.reload(module)
.2 : Python 3.2 - 3.3 :imp.reload(module)
Python 2:reload(module)

if 'myModule' in sys.modules:  
    del sys.modules["myModule"]

다음 코드는 Python 2/3 호환성을 허용합니다.

try:
    reload
except NameError:
    # Python 3
    from imp import reload

는 '어디서든 상관없다'로 쓸 수 있다.reload()두 버전 모두 쉽게 만들 수 있습니다.

접수된 답변에서는 X로부터의 Import Y 케이스는 처리되지 않습니다.이 코드는 이 코드와 표준 Import 케이스도 처리합니다.

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")

새로고침의 경우 새로고침된 모듈에 저장된 값에 최상위 이름을 재할당하여 새로고침된 모듈을 업데이트합니다.

서버에 있는 것이 아니라 모듈을 개발 중이고 모듈을 자주 새로고침해야 하는 경우, 여기 좋은 힌트가 있습니다.

먼저 Jupyter 노트북 프로젝트의 우수한 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.

물론 주피터 노트북에서도 사용할 수 있습니다.

모듈을 새로고침하는 현대적인 방법은 다음과 같습니다.

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이 메서드는 모듈을 새로고침하기 위해 호출할 수 있습니다.를 들어, 「」라고 하는 것은,reload(math) 됩니다.math★★★★★★ 。

나와 같은 모든 모듈을 언로드하고 싶은 경우(Emacs에서 Python 인터프리터로 실행할 경우):

   for mod in sys.modules.values():
      reload(mod)

자세한 내용은 Python 모듈 새로고침에 있습니다.

편집(V2에 응답)

정보만 수 하는 것은 (리셋 정보보다 큼).reload필요조건보다 적습니다).실제로 모든 레퍼런스를 설정하기 위해서는 가비지 컬렉터로 이동하여 레퍼런스를 다시 작성해야 했습니다.!!그 !!!!!!!!!!!

GC가 꺼져 있는 경우 또는 GC에 의해 모니터링되지 않는 데이터를 새로고침하는 경우 이 기능은 작동하지 않습니다.GC를 조작하고 싶지 않은 경우는, 원래의 회답으로 충분합니다.

새 코드:

import importlib
import inspect
import gc
from enum import EnumMeta
from weakref import ref


_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.
    """

    # 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 쓰죠.importlib의 »reload모든 선언된 모듈의 속성을 재귀적으로 덮어씁니다.Python 6 3 . 6 。

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에서 내부 문제(피클링/피클링 해제 문제 등)가 발생할 수 있습니다.

Enthouted Features에는 이에 적합한 모듈이 있습니다.https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html

변경된 모듈을 새로고침하고 해당 모듈을 사용하는 다른 모듈 및 인스턴스 개체를 업데이트합니다.에서는 대부분의 경우 동작하지 않습니다.__very_private__메서드 및 클래스 상속으로 인해 질식할 수 있지만 PyQt guis 또는 Maya나 Nuke와 같은 프로그램 내에서 실행되는 데이터를 작성할 때 호스트 애플리케이션을 재시작해야 하는 시간을 크게 절약할 수 있습니다.아마 20~30%는 효과가 없을 것입니다만, 여전히 매우 도움이 됩니다.

Enthought의 패키지는 파일이 변경되는 즉시 새로고침되지 않습니다(명확하게 불러야 합니다). 그러나 이것이 정말로 필요한 경우 구현하기가 그리 어렵지 않습니다.

Python 디폴트 Python참조주세요.importlib.reload인수로 전달된 라이브러리를 다시 가져옵니다.lib가 Import한 라이브러리는 새로고침되지 않습니다.많은 파일을 변경하고 Import할 패키지가 다소 복잡한 경우 완전 새로고침을 수행해야 합니다.

IPython 또는 Jupyter가 설치되어 있는 경우 함수를 사용하여 모든 lib를 새로고침할 수 있습니다.

from IPython.lib.deepreload import reload as dreload
dreload(foo)

Jupyter가 없는 경우 셸에 다음 명령을 사용하여 설치합니다.

pip3 install jupyter

python 3을 사용하여 importlib에서 새로고침하는 사용자.

모듈이 새로고침되지 않는 것처럼 보이는 문제가 있는 경우...pyc 재컴파일(최대 60초)에 시간이 걸리기 때문입니다.이런 문제를 겪으신 적이 있는지 알려드리기 위해 힌트를 드립니다.

2018-02-01

  1. 「」foo수입하다
  2. from importlib import reload,reload(foo)

31.5. importlib : Import 구현 - Python 3.6.4 매뉴얼

아바쿠스의 경우엔 그게 작동 방식이에요파일이 Class_VerticesEdges라고 가정합니다.화이

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'])

다음의 에러가 발생했을 경우는, 이 회답이 해결 방법에 도움이 되는 경우가 있습니다.

트레이스백(최신 콜의 마지막): 
파일 "FFFF", 줄 1, 입력Name Error: 이름 'YYY'는 정의되어 있지 않습니다.

또는

트레이스백(최신 콜의 마지막):
파일 "FFFF", 줄 1, 입력파일 "/usr/local/lib/python 3.7/importlib/_init_.py", 140행 새로고침 중raise TypeError("reload() 인수는 모듈이어야 함)TypeError: reload() 인수는 모듈이어야 합니다.

Import를 수 있습니다.sys.modules새로고침할 모듈을 가져오려면 다음 절차를 수행합니다.

  import importlib
  import sys

  from YYYY.XXX.ZZZ import CCCC
  import AAA.BBB.CC


  def reload(full_name)
    if full_name in sys.modules:
      importlib.reload(sys.modules[full_name])


  reload('YYYY.XXX.ZZZ') # this is fine in both cases
  reload('AAA.BBB.CC')  

  importlib.reload(YYYY.XXX.ZZZ) # in my case: this fails
  importlib.reload(AAA.BBB.CC)   #             and this is ok

큰 는 '이러한 문제라는 입니다.importlib.reload는 문자열이 아닌 모듈만 받아들입니다.

sys.modules에서 모듈을 삭제하려면 '없음' 유형도 삭제해야 합니다.

방법 1:

import sys
import json  ##  your module

for mod in [ m for m in sys.modules if m.lstrip('_').startswith('json') or sys.modules[m] == None ]: del sys.modules[mod]

print( json.dumps( [1] ) )  ##  test if functionality has been removed

방법 2: 부기 엔트리를 사용하여 모든 의존관계를 삭제합니다.

import sys

before_import = [mod for mod in sys.modules]
import json  ##  your module
after_import = [mod for mod in sys.modules if mod not in before_import]

for mod in [m for m in sys.modules if m in after_import or sys.modules[m] == None]: del sys.modules[mod]

print( json.dumps( [2] ) )  ##  test if functionality has been removed

옵션입니다만, 모든 엔트리가 아웃이 되어 있는 것을 확인합니다.선택할 경우:

import gc
gc.collect()

Python은 다음과 같은 경우 서브모듈 주소를 재계산하지 않습니다.reload 있는 )sys.modules

완벽하지는 않지만 효과가 있는 회피책이 있습니다.

# Created by BaiJiFeiLong@gmail.com at 2022/2/19 18:50
import importlib
import types

import urllib.parse
import urllib.request


def reloadModuleWithChildren(mod):
    mod = importlib.reload(mod)
    for k, v in mod.__dict__.items():
        if isinstance(v, types.ModuleType):
            setattr(mod, k, importlib.import_module(v.__name__))


fakeParse = types.ModuleType("urllib.parse")
realParse = urllib.parse

urllib.parse = fakeParse
assert urllib.parse is fakeParse

importlib.reload(urllib)
assert urllib.parse is fakeParse
assert getattr(urllib, "parse") is fakeParse

reloadModuleWithChildren(urllib)
assert urllib.parse is not fakeParse
assert urllib.parse is realParse

다른 방법으로는 함수로 모듈을 Import할 수 있습니다.이렇게 함수가 완료되면 모듈이 가비지 수집됩니다.

Text에서 을 새로고침하는 데 만, 이 에 대한 수. Sublime Text에 코드는 Sublime Text에 합니다.sublime_plugin.py를 사용하여 모듈을 새로고침합니다.

다음 절차에서는 이름에 공백이 있는 경로에서 모듈을 새로고침할 수 있습니다.그 후 새로고침 후에는 통상대로 Import만 할 수 있습니다.

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()이치노포함 (숭고문 포함)Python 3.3.6닫히지 한).Python3.3★★★★★★★★★★★★★★★★★★」

언급URL : https://stackoverflow.com/questions/437589/how-do-i-unload-reload-a-python-module

반응형