Làm cách nào để tôi tải (tải lại) một mô-đun?


797

Tôi có một máy chủ Python hoạt động lâu dài và muốn có thể nâng cấp dịch vụ mà không cần khởi động lại máy chủ. Cách tốt nhất để làm điều này là gì?

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

53
Mẹo ghi nhớ: "nhập" không có nghĩa là "tải", nó có nghĩa là "tải nếu chưa được tải và sau đó nhập vào không gian tên".
Kos

3
câu hỏi không nên bao gồm 'unload' vì điều đó là không thể có trong python - tuy nhiên tải lại là một mô hình đã biết như được trả lời dưới đây
robertmoggach

Tôi gặp vấn đề tương tự khi sử dụng mô-đun động trong ứng dụng py2exe. Vì py2exe luôn giữ mã byte trong thư mục zip tải lại không hoạt động. Nhưng tôi đã tìm thấy một giải pháp làm việc bằng cách sử dụng mô-đun import_file. Bây giờ ứng dụng của tôi đang hoạt động tốt.
Pritam Pan

2
Điều gì xảy ra nếu bạn muốn "dỡ tải" vì cố gắng xóa tệp .pyc đang được sử dụng bởi mã?
bóng tối

Câu trả lời:


792

Bạn có thể tải lại một mô-đun khi nó đã được nhập bằng cách sử dụng reloadhàm dựng sẵn (chỉ dành cho Python 3,4+) :

from importlib import reload  
import foo

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

Trong Python 3, reloadđã được chuyển đến impmô-đun. Trong 3,4, impđã không được ủng hộ importlibreloadđược thêm vào sau này. Khi nhắm mục tiêu 3 trở lên, hãy tham chiếu mô-đun thích hợp khi gọi reloadhoặc nhập mô-đun .

Tôi nghĩ rằng đây là những gì bạn muốn. Các máy chủ web như máy chủ phát triển của Django sử dụng điều này để bạn có thể thấy tác động của các thay đổi mã của mình mà không cần khởi động lại quy trình máy chủ.

Để trích dẫn từ các tài liệu:

Mã của mô-đun Python được biên dịch lại và mã cấp mô-đun được kiểm tra lại, xác định một bộ đối tượng mới được liên kết với tên trong từ điển của mô-đun. Hàm init của các mô đun mở rộng không được gọi là lần thứ hai. Như với tất cả các đối tượng khác trong Python, các đối tượng cũ chỉ được thu hồi sau khi số tham chiếu của chúng giảm xuống không. Các tên trong không gian tên mô-đun được cập nhật để trỏ đến bất kỳ đối tượng mới hoặc thay đổi. Các tham chiếu khác đến các đối tượng cũ (chẳng hạn như tên bên ngoài mô-đun) không được bật lại để tham chiếu đến các đối tượng mới và phải được cập nhật trong mỗi không gian tên nơi chúng xảy ra nếu muốn.

Như bạn đã lưu ý trong câu hỏi của mình, bạn sẽ phải xây dựng lại Foocác đối tượng nếu Foolớp nằm trong foomô-đun.


10
trên thực tế, django dev khởi động lại máy chủ bản thân khi bạn thay đổi một tập tin .. (nó khởi động lại máy chủ, không chỉ tải lại các module)
Hasen

25
Hàm "is_changed" này đến từ đâu? tôi thấy không có tài liệu nào về nó và nó không chạy trong môi trường Python 3.1.3 của tôi, nó cũng không chạy trong 2.6.4.
jedmao

5
không có cdleary, Django không thể chỉ sử dụng tải lại: pyunit.sourceforge.net/notes/reloading.html
raylu

14
@BartoszKP nếu Xkhông phải là một mô-đun, bạn có thểimport sys; reload(sys.modules[X.__module__])
drevicko

5
@jedmao @JamesDraper Tôi khá chắc chắn rằng is_changedhàm này chỉ là một hàm tùy ý mà bạn sẽ phải viết; nó không phải là một tích hợp. Ví dụ, nó có thể có thể mở tệp tương ứng với mô-đun mà bạn đang nhập và tìm khác với phiên bản được lưu trong bộ nhớ cache để xem nó có thay đổi không.
James Mchugh

252

Trong Python 3.0 Ném3.3 bạn sẽ sử dụng: imp.reload(module)

Các BDFL đã trả lời câu hỏi này.

Tuy nhiên, impđã không được chấp nhận trong 3,4, ủng hộimportlib (cảm ơn @Stefan! ).

Tôi nghĩ , do đó, bây giờ bạn sẽ sử dụng importlib.reload(module), mặc dù tôi không chắc chắn.


23
Người mới nghiêm túc rất biết ơn khi tìm hiểu về các sắc thái quan trọng giữa Python 2 và 3.
Smandoli

24
imp.reload (imp) có hợp lệ không?
Loïc Faure-Lacroix

2
@ LoïcFaure-Lacroix theo cách tương tự reload(__builtins__)có hiệu lực trong 2.x
JBernardo

1
@Tarrasch: đó là mô-đun Python mà bạn muốn tải lại, như trong ví dụ trong câu hỏi.
Paul D. Chờ

3
@ LoïcFaure-Lacroix vâng, imp có thể tự tải lại.
Devyn Collier Johnson

92

Có thể đặc biệt khó xóa một mô-đun nếu nó không phải là Python thuần túy.

Đây là một số thông tin từ: Làm thế nào để tôi thực sự xóa một mô-đun nhập khẩu?

Bạn có thể sử dụng sys.getrefcount () để tìm hiểu số lượng tài liệu tham khảo thực tế.

>>> import sys, empty, os
>>> sys.getrefcount(sys)
9
>>> sys.getrefcount(os)
6
>>> sys.getrefcount(empty)
3

Các số lớn hơn 3 chỉ ra rằng sẽ khó thoát khỏi mô-đun. Mô-đun "trống" trong nhà (không chứa gì) nên được thu gom rác sau

>>> del sys.modules["empty"]
>>> del empty

vì tham chiếu thứ ba là một tạo phẩm của hàm getrefcount ().


4
Tôi mới phát hiện ra rằng nếu mô-đun là một phần của gói, bạn cũng phải xóa nó ở đó:setattr(package, "empty", None)
u0b34a0f6ae

6
Đây là giải pháp chính xác, đặc biệt nếu bạn có một gói với các mô-đun lồng nhau. reload()chỉ tải lại mô-đun cao nhất và mọi thứ bên trong nó sẽ không được tải lại trừ khi bạn xóa nó lần đầu tiên khỏi sys.modules.
Cerin

73

reload(module), nhưng chỉ khi nó hoàn toàn độc lập. Nếu bất cứ điều gì khác có liên quan đến mô-đun (hoặc bất kỳ đối tượng nào thuộc mô-đun), thì bạn sẽ gặp các lỗi tinh vi và tò mò do mã cũ treo xung quanh lâu hơn bạn mong đợi và những thứ như isinstancekhông hoạt động trên các phiên bản khác nhau của cùng mã.

Nếu bạn có phụ thuộc một chiều, bạn cũng phải tải lại tất cả các mô-đun phụ thuộc vào mô-đun được tải lại để thoát khỏi tất cả các tham chiếu đến mã cũ. Và sau đó tải lại các mô-đun phụ thuộc vào các mô-đun được tải lại, đệ quy.

Nếu bạn có các phụ thuộc vòng tròn, điều rất phổ biến, ví dụ như khi bạn đang xử lý tải lại một gói, bạn phải dỡ tất cả các mô-đun trong nhóm trong một lần. Bạn không thể làm điều này với reload()vì nó sẽ nhập lại từng mô-đun trước khi các phụ thuộc của nó được làm mới, cho phép các tham chiếu cũ len vào các mô-đun mới.

Cách duy nhất để làm điều đó trong trường hợp này là hack sys.modules, đây là loại không được hỗ trợ. Bạn phải trải qua và xóa từng sys.modulesmục bạn muốn được tải lại trong lần nhập tiếp theo và cũng xóa các mục có giá trị Noneđể xử lý vấn đề triển khai để thực hiện với bộ đệm tương đối không nhập. Nó không đẹp lắm nhưng miễn là bạn có một bộ phụ thuộc hoàn toàn khép kín mà không để các tham chiếu bên ngoài cơ sở mã của nó, thì nó hoàn toàn khả thi.

Có lẽ tốt nhất để khởi động lại máy chủ. :-)


1
Không tải cụ thể cho kịch bản đó?
Josh

@Josh: không, đó là để tải lại một cây gói, và thậm chí sau đó nó chỉ hoạt động miễn là gói không có phụ thuộc bên ngoài / vòng tròn.
bobince

1
Bạn có thể xây dựng phần với Nonecác giá trị vì tôi đang xử lý chính xác vấn đề này: Tôi đang xóa các mục từ sys.modulesvà sau khi nhập lại một số phụ thuộc đã nhập None.
schlamar

@shclamar: Xem stackoverflow.com/questions/1958417/ trên (và các liên kết từ đó) để biết nền. Tôi không rõ (thậm chí nhìn vào mã import.c) cách các Nonemục được quản lý để quay trở lại thông qua cơ chế nhập khi các mục 'thực' bị xóa và dường như tôi không thể thực hiện được vào ngày 2.7; trong tương lai chắc chắn nó không còn là vấn đề nữa vì hàng nhập khẩu tương đối đã biến mất. Trong khi đó, xóa tất cả các mục có Nonegiá trị dường như sẽ khắc phục nó.
bobince

1
@Eliethesaiyan: ý bạn là reloadchức năng? Nó được tích hợp sẵn, bạn không phải nhập bất kỳ thư viện nào.
bobince

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

3
+1. Mục tiêu của tôi là chạy thử mũi trong trăn. Sau khi tôi đã tải một mô-đun và đổi tên một số chức năng, các tên cũ vẫn còn khi gọi nose.run(), ngay cả sau đóreload(my_module) %run my_module
Peter D

5
Nếu mô-đun của bạn nhập các mô-đun riêng của nó, bạn cũng có thể cần phải xóa chúng. Một cái gì đó như [del(sys.modules[mod] for mod in sys.modules.keys() if mod.startswith('myModule.')].
drevicko

Tôi không nghĩ rằng dỡ bỏ mô-đun. Trên Python 3.8: import sys; import json; del sys.modules['json']; print(json.dumps([1]))và mô-đun json vẫn hoạt động mặc dù nó không còn trong sys.modules nữa.
Seperman

60

Đối với Python 2, sử dụng hàm tích hợp tải lại () :

reload(module)

Đối với Python 2 và 3.2, 3.13, sử dụng tải lại từ mô-đun imp :

import imp
imp.reload(module)

Nhưng imp không được chấp nhận kể từ phiên bản 3.4 có lợi cho importlib , vì vậy hãy sử dụng:

import importlib
importlib.reload(module)

hoặc là

from importlib import reload
reload(module)

2
để xử lý bất kỳ trường hợp nào sau đây: from six import reload_module( pip install sixtất nhiên là trước tiên)
Anentropic

@Anentropic: Lời khuyên tốt là khuyên bạn nên sử dụng sáu gói, nhưng cú pháp là from six.moves import reload_module( doc )
x0s

23

Đoạn mã sau cho phép bạn tương thích Python 2/3:

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

Bạn có thể sử dụng nó như reload()trong cả hai phiên bản, điều này làm cho mọi thứ đơn giản hơn.


18

Câu trả lời được chấp nhận không xử lý trường hợp X nhập Y. Mã này xử lý nó và trường hợp nhập tiêu chuẩn là tốt:

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

Trong trường hợp tải lại, chúng tôi gán lại tên cấp cao nhất cho các giá trị được lưu trữ trong mô-đun mới được tải lại, cập nhật chúng.


Nhận thấy một vấn đề, globalals () đề cập đến mô-đun bạn xác định hàm này, vì vậy nếu bạn xác định nó trong một mô-đun khác với mô-đun bạn gọi nó trong mô-đun này thì không hoạt động.
Joseph Garvin

Để tương tác, sau khi >>> from X import Ytải lại làm>>> __import__('X', fromlist='Y')
Bob Stein

@ BobStein-VisiBone, có cách nào để thực hiện công việc đó khi fromlist='*'nào?
Mike C

Câu hỏi hay, không biết @MikeC. Nhân tiện, tôi đang có xu hướng ngừng gần như tất cả việc sử dụng fromtrong báo cáo nhập khẩu. Chỉ cần stark import <package>và rõ ràng gói.symbol trong mã. Nhận ra điều này có thể không phải luôn luôn có thể hoặc mong muốn. (Đây là một ngoại lệ: từ print_feft nhập trong tương lai.)
Bob Stein

Mike C: những gì làm việc cho tôi làfoo = reload(foo); from foo import *
hung hăng

16

Đây là cách hiện đại để tải lại một mô-đun:

from importlib import reload

Nếu bạn muốn hỗ trợ các phiên bản Python cũ hơn 3,5, hãy thử điều này:

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+

Để sử dụng nó, hãy chạy reload(MODULE), thay thế MODULEbằng mô-đun bạn muốn tải lại.

Ví dụ, reload(math)sẽ tải lại mathmô-đun.


4
Hoặc chỉ cần làm from importlib import reload. Sau đó, bạn có thể làm reload(MODULE_NAME). Không cần cho chức năng này.
pault

Tôi tin modulereload(MODULE_NAME)là tự giải thích nhiều hơn chỉ reload(MODULE_NAME)và có cơ hội xung đột với các chức năng khác thấp hơn.
Richie Bendall

@RichieBendall Xin lỗi, nhưng câu trả lời này là hoàn toàn sai. Reload () chức năng có đối tượng mô-đun, tên không mô-đun ... Đọc tài liệu: docs.python.org/3/library/importlib.html#importlib.reload Và tôi đồng ý với @ pault - đây "như modulereload" là thành vô .
mbdevpl

Tôi đã thay đổi câu trả lời của tôi để phản ánh ý kiến ​​của bạn.
Richie Bendall

13

Nếu bạn không ở trong một máy chủ, nhưng đang phát triển và cần thường xuyên tải lại một mô-đun, đây là một mẹo hay.

Trước tiên, hãy chắc chắn rằng bạn đang sử dụng trình bao IPython tuyệt vời , từ dự án Jupyter Notebook. Sau khi cài đặt Jupyter, bạn có thể khởi động nó ipython, hoặc jupyter console, hoặc thậm chí tốt hơn, jupyter qtconsolesẽ cung cấp cho bạn một giao diện điều khiển được tô màu đẹp với hoàn thành mã trong bất kỳ HĐH nào.

Bây giờ trong vỏ của bạn, gõ:

%load_ext autoreload
%autoreload 2

Bây giờ, mỗi khi bạn chạy tập lệnh của mình, các mô-đun của bạn sẽ được tải lại.

Ngoài ra 2, còn có các tùy chọn khác của phép thuật tự động tải :

%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.

7

Đối với những người như tôi muốn dỡ tất cả các mô-đun (khi chạy trong trình thông dịch Python trong Emacs ):

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

Thông tin thêm có trong Tải lại các mô-đun Python .


Trên thực tế, điều đó dường như không hoạt động đáng tin cậy (trong 2.6) vì không phải mọi thứ trong sys.modules.values()đều là một mô-đun. Ví dụ: >>> type (sys.modules.values ​​() [1]) <class 'email.LazyImporter'> Vì vậy, nếu tôi cố chạy mã đó, nó sẽ rơi xuống (Tôi biết nó không có nghĩa là một giải pháp thực tế, chỉ là chỉ ra rằng).
Francis Davey

Nó thậm chí không hoạt động trong những con trăn trước đó - như đã viết. Tôi đã phải loại trừ một số tên. Tôi sẽ cập nhật bài viết khi tôi chuyển mã đó sang máy tính mới của mình.

2
Hoạt động tốt trong Python 2.7 sau một số sửa đổi:if mod and mod.__name__ != "__main__": imp.reload(mod)
Czarek Tomczak

2
Điều này hoạt động tốt với tôi: nhập imp [tải lại (m) cho m trong sys.modules.values ​​() nếu m và không " " trong m .__ tên và không imp.is_builtin (m .__ name__)]
Patrick Wolf

5

Enth think Traits có một mô-đun hoạt động khá tốt cho việc này. https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html

Nó sẽ tải lại bất kỳ mô-đun nào đã được thay đổi, và cập nhật các mô-đun khác và các đối tượng được kích hoạt đang sử dụng nó. Nó không hoạt động hầu hết thời gian với __very_private__các phương thức và có thể làm nghẹt kế thừa lớp, nhưng nó giúp tôi tiết kiệm thời gian điên rồ khi phải khởi động lại ứng dụng máy chủ khi viết guQ PyQt, hoặc những thứ chạy bên trong các chương trình như Maya hoặc Nuke. Nó không hoạt động có thể 20-30% thời gian, nhưng nó vẫn cực kỳ hữu ích.

Gói của Enth think không tải lại các tệp ngay khi chúng thay đổi - bạn phải gọi nó một cách rõ ràng - nhưng đó không phải là tất cả khó thực hiện nếu bạn thực sự cần nó


5

Những người đang sử dụng python 3 và tải lại từ importlib.

Nếu bạn gặp vấn đề như có vẻ như mô-đun không tải lại ... Đó là bởi vì nó cần một chút thời gian để biên dịch lại pyc (tối đa 60 giây). Tôi viết gợi ý này chỉ để bạn biết nếu bạn đã gặp phải loại vấn đề này.



3

Tùy chọn khác. Xem rằng mặc định Python importlib.reloadsẽ chỉ nhập lại thư viện được truyền dưới dạng đối số. Nó sẽ không tải lại các thư viện mà lib nhập của bạn. Nếu bạn đã thay đổi rất nhiều tệp và có một gói hơi phức tạp để nhập, bạn phải tải lại sâu .

Nếu bạn đã cài đặt IPython hoặc Jupyter , bạn có thể sử dụng một chức năng để tải lại sâu tất cả các lib:

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

Nếu bạn không có Jupyter, hãy cài đặt nó bằng lệnh này trong trình bao của bạn:

pip3 install jupyter

Cả Ipython dreload và reload () từ importlib đều phàn nàn với reload() argument must be module. Tôi đang sử dụng chức năng nhập tùy chỉnh và dường như không hoạt động. Sử dụng các mô-đun tích hợp không hoạt động. :-( thật lãng phí thời gian khi tải lại iPython cho mỗi thay đổi nhỏ mà tôi đã thực hiện đối với mã của mình ...
m3nda

2

Chỉnh sửa (Trả lời V2)

Giải pháp từ trước là tốt cho việc chỉ lấy thông tin đặt lại, nhưng nó sẽ không thay đổi tất cả các tham chiếu (nhiều hơn reloadnhưng ít hơn yêu cầu). Để thực sự thiết lập tất cả các tài liệu tham khảo, tôi đã phải đi vào trình thu gom rác và viết lại các tài liệu tham khảo ở đó. Bây giờ nó hoạt động như một nét duyên dáng!

Lưu ý rằng điều này sẽ không hoạt động nếu tắt GC hoặc nếu tải lại dữ liệu không được giám sát bởi GC. Nếu bạn không muốn gây rối với GC, câu trả lời ban đầu có thể là đủ cho bạn.

Mã mới:

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)

Câu trả lời gốc

Như được viết trong câu trả lời của @ bobince, nếu đã có một tham chiếu đến mô-đun đó trong một mô-đun khác (đặc biệt là nếu nó được nhập với astừ khóa như import numpy as np), thì trường hợp đó sẽ không bị ghi đè.

Điều này tỏ ra khá khó khăn với tôi khi áp dụng các thử nghiệm yêu cầu trạng thái "sạch sẽ" của các mô-đun cấu hình, vì vậy tôi đã viết một hàm có tên reset_modulelà sử dụng chức năng importlibcủa reloadnó và ghi đè lên tất cả các thuộc tính của mô-đun được khai báo. Nó đã được thử nghiệm với phiên bản Python 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

Lưu ý: Sử dụng cẩn thận! Việc sử dụng chúng trên các mô-đun không ngoại vi (ví dụ mô-đun xác định các lớp được sử dụng bên ngoài) có thể dẫn đến các vấn đề nội bộ trong Python (chẳng hạn như các vấn đề tẩy / không tẩy).


1

Đối với tôi đối với trường hợp của Abaqus, đó là cách nó hoạt động. Hãy tưởng tượng tệp của bạn là 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'])

Câu trả lời này là một bản sao trực tiếp từ đây: ebanshi.cc/questions/1942/ Kẻ
SiHa

0

Tôi đã gặp nhiều rắc rối khi cố tải lại một cái gì đó bên trong Sublime Text, nhưng cuối cùng tôi có thể viết tiện ích này để tải lại các mô-đun trên Sublime Text dựa trên mã sublime_plugin.pysử dụng để tải lại các mô-đun.

Điều này dưới đây chấp nhận bạn tải lại các mô-đun từ các đường dẫn có khoảng trắng trên tên của chúng, sau đó sau khi tải lại, bạn có thể nhập như bạn thường làm.

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

Nếu bạn chạy lần đầu tiên, điều này sẽ tải mô-đun, nhưng nếu sau này bạn có thể lại phương thức / chức năng run_tests()thì nó sẽ tải lại các tệp kiểm tra. Với Sublime Text ( Python 3.3.6) điều này xảy ra rất nhiều vì trình thông dịch của nó không bao giờ đóng (trừ khi bạn khởi động lại Sublime Text, tức là trình Python3.3thông dịch).


-1

Một cách khác có thể là nhập mô-đun trong một chức năng. Cách này khi chức năng hoàn thành mô-đun được thu gom rác.


4
Mô-đun sẽ không bao giờ thu gom rác vì tham chiếu toàn cầu được tổ chức ít nhất là trong sys.modules.
Tất cả công nhân là cần thiết
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.