ฉันมีเซิร์ฟเวอร์ 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
ฟังก์ชัน builtin (Python 3.4+ เท่านั้น) :
from importlib import reload
import foo
while True:
# Do some things.
if is_changed(foo):
foo = reload(foo)
ใน Python 3 reload
ถูกย้ายไปที่imp
โมดูล ใน 3.4 imp
ถูกคัดค้านimportlib
และreload
ถูกเพิ่มเข้ามาในภายหลัง เมื่อกำหนดเป้าหมาย 3 หรือใหม่กว่าให้อ้างอิงโมดูลที่เหมาะสมเมื่อโทรreload
หรือนำเข้า
ฉันคิดว่านี่คือสิ่งที่คุณต้องการ เว็บเซิร์ฟเวอร์เช่นเซิร์ฟเวอร์การพัฒนาของ Django ใช้สิ่งนี้เพื่อให้คุณสามารถเห็นผลกระทบของการเปลี่ยนแปลงรหัสของคุณโดยไม่ต้องรีสตาร์ทกระบวนการเซิร์ฟเวอร์เอง
อ้างจากเอกสาร:
รหัสโมดูลของ Python นั้นจะถูกคอมไพล์ใหม่และโค้ดระดับโมดูลจะถูกเปิดใช้งานใหม่โดยกำหนดชุดของออบเจกต์ใหม่ที่เชื่อมโยงกับชื่อในพจนานุกรมของโมดูล ฟังก์ชั่น init ของส่วนขยายโมดูลไม่ได้เรียกว่าครั้งที่สอง เช่นเดียวกับวัตถุอื่น ๆ ใน Python วัตถุเก่าจะถูกเรียกคืนเฉพาะหลังจากการนับการอ้างอิงของพวกเขาลดลงถึงศูนย์ ชื่อในโมดูลเนมสเปซได้รับการปรับปรุงให้ชี้ไปที่วัตถุใหม่หรือที่เปลี่ยนแปลง การอ้างอิงอื่น ๆ ไปยังวัตถุเก่า (เช่นชื่อภายนอกโมดูล) จะไม่ตอบสนองเพื่ออ้างอิงถึงวัตถุใหม่และต้องอัปเดตในแต่ละเนมสเปซที่เกิดขึ้นหากต้องการ
ดังที่คุณจดไว้ในคำถามของคุณคุณจะต้องสร้างFoo
วัตถุใหม่ถ้าFoo
ชั้นเรียนอยู่ในfoo
โมดูล
X
ไม่ใช่โมดูลคุณสามารถimport sys; reload(sys.modules[X.__module__])
is_changed
ฟังก์ชั่นเป็นเพียงฟังก์ชั่นที่คุณต้องเขียน; มันไม่ใช่ในตัว ตัวอย่างเช่นมันอาจจะเปิดไฟล์ที่สอดคล้องกับโมดูลที่คุณกำลังนำเข้าและ diff กับรุ่นแคชเพื่อดูว่ามันมีการเปลี่ยนแปลง
ใน Python 3.0–3.3 คุณจะใช้: imp.reload(module)
อย่างไรก็ตาม imp
ถูกคัดค้านใน 3.4 ตามimportlib
(ขอบคุณ@Stefan! )
ฉันคิดว่าดังนั้นตอนนี้คุณจะใช้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
จะจัดการกับปัญหาการใช้งานจะทำอย่างไรกับการแคชล้มเหลวในการนำเข้าญาติ มันไม่ได้ดีมากนัก แต่ตราบใดที่คุณมีชุดอ้างอิงที่สมบูรณ์แบบในตัวเองที่ไม่ทิ้งการอ้างอิงไว้นอก codebase มันสามารถใช้งานได้
อาจเป็นการดีที่สุดที่จะรีสตาร์ทเซิร์ฟเวอร์ :-)
None
ค่าได้ไหมเพราะฉันพบปัญหานี้อย่างแน่นอน: ฉันกำลังลบรายการจากsys.modules
และหลังจากนำเข้าการอ้างอิงที่นำเข้ามาNone
อีกครั้ง
None
รายการจัดการเพื่อย้อนกลับผ่านกลไกการนำเข้าเมื่อรายการ 'ของจริง' ถูกลบไปแล้วและฉันไม่สามารถทำให้มันเกิดขึ้นได้ใน 2.7; ในอนาคตแน่นอนว่ามันจะไม่มีปัญหาอีกต่อไปเนื่องจากการนำเข้าญาติโดยนัยหายไป ในระหว่างนี้การลบรายการทั้งหมดที่มี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(module)
สำหรับ Python 2 และ 3.2–3.3 ให้ใช้การโหลดซ้ำจากโมดูล imp :
import imp
imp.reload(module)
แต่imp
เลิกใช้แล้วตั้งแต่เวอร์ชัน 3.4 เพื่อใช้กับimportlibดังนั้นใช้:
import importlib
importlib.reload(module)
หรือ
from importlib import reload
reload(module)
from six import reload_module
(ต้องเรียนpip install six
ก่อน)
รหัสต่อไปนี้ช่วยให้คุณสามารถใช้งาน Python 2/3 ได้:
try:
reload
except NameError:
# Python 3
from imp import reload
คุณสามารถใช้มันreload()
ในทั้งสองเวอร์ชันซึ่งทำให้สิ่งต่าง ๆ ง่ายขึ้น
คำตอบที่ยอมรับไม่ได้จัดการกรณี X จากการนำเข้า 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 ชัดเจนในรหัส ตระหนักว่าสิ่งนี้อาจไม่เป็นไปได้หรือเป็นที่ต้องการเสมอไป (นี่คือข้อยกเว้นหนึ่งข้อ: จากการนำเข้า print_function ในอนาคต)
foo = reload(foo); from foo import *
นี่เป็นวิธีที่ทันสมัยในการโหลดโมดูล:
from importlib import reload
ถ้าคุณต้องการสนับสนุน Python เวอร์ชันที่เก่ากว่า 3.5 ลองสิ่งนี้:
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)
และมีโอกาสน้อยกว่าที่จะขัดแย้งกับหน้าที่อื่น ๆ
หากคุณไม่ได้อยู่ในเซิร์ฟเวอร์ แต่กำลังพัฒนาและจำเป็นต้องโหลดโมดูลบ่อยครั้งนี่เป็นคำแนะนำที่ดี
ขั้นแรกให้แน่ใจว่าคุณใช้เปลือก IPython ที่ยอดเยี่ยมจากโครงการ Jupyter Notebook หลังจากติดตั้ง Jupyter คุณสามารถเริ่มต้นด้วยipython
หรือjupyter console
หรือดียิ่งขึ้นjupyter qtconsole
ซึ่งจะให้คอนโซลที่มีสีสันดีพร้อมโค้ดที่สมบูรณ์ในระบบปฏิบัติการใด ๆ
ตอนนี้ในเชลล์ของคุณพิมพ์:
%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.
สำหรับคนอย่างฉันที่ต้องการยกเลิกการโหลดโมดูลทั้งหมด (เมื่อทำงานใน Python interpreter ภายใต้Emacs ):
for mod in sys.modules.values():
reload(mod)
sys.modules.values()
นั้นเป็นโมดูล ตัวอย่างเช่น: >>> type (sys.modules.values () [1]) <class 'email.LazyImporter'> ดังนั้นถ้าฉันพยายามเรียกใช้รหัสนั้นมันจะตก (ฉันรู้ว่ามันไม่ได้เป็นวิธีการแก้ปัญหาเพียงแค่ ชี้ไปที่นั้น)
if mod and mod.__name__ != "__main__": imp.reload(mod)
คุณลักษณะความคิดมีโมดูลที่ทำงานค่อนข้างดีสำหรับเรื่องนี้ https://traits.readthedocs.org/en/4.3.0/_modules/traits/util/refresh.html
มันจะโหลดโมดูลใด ๆ ที่มีการเปลี่ยนแปลงและอัปเดตโมดูลอื่น ๆ และวัตถุที่ไม่ได้ใช้ที่กำลังใช้งานอยู่ มันใช้งานไม่ได้กับ__very_private__
วิธีการส่วนใหญ่และสามารถทำให้หายใจไม่ออกในชั้นเรียนได้ แต่มันช่วยประหยัดเวลาได้อย่างมากที่ฉันไม่ต้องรีสตาร์ทแอปพลิเคชั่นโฮสต์เมื่อเขียน PyQt guis หรือสิ่งที่ทำงานภายในโปรแกรมเช่น Maya หรือ Nuke อาจไม่ได้ผลประมาณ 20-30% แต่ก็ยังมีประโยชน์อย่างไม่น่าเชื่อ
แพคเกจของแม้จะไม่โหลดไฟล์ทันทีที่มีการเปลี่ยนแปลง - คุณต้องเรียกมันอย่างชัดเจน - แต่มันไม่ควรที่จะนำไปใช้ทั้งหมดหากคุณต้องการมันจริงๆ
ผู้ที่ใช้ python 3 และโหลดซ้ำจาก importlib
หากคุณมีปัญหาเหมือนว่าโมดูลไม่โหลดซ้ำ ... นั่นเป็นเพราะมันต้องใช้เวลาในการคอมไพล์ pyc (ไม่เกิน 60 วินาที) ฉันเขียนคำแนะนำนี้เพียงแค่คุณรู้ว่าคุณประสบปัญหาแบบนี้หรือไม่
2018/02/01
foo
ต้องนำเข้าโมดูลสำเร็จล่วงหน้า from importlib import reload
, reload(foo)
ตัวเลือกอื่น ๆ ดูว่าค่าเริ่มต้นของ Python 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
) อินสแตนซ์นั้นจะไม่ถูกเขียนทับ
สิ่งนี้พิสูจน์ให้เห็นแล้วว่าเป็นปัญหาสำหรับฉันเมื่อใช้การทดสอบที่ต้องการสถานะ "clean-slate" ของโมดูลการกำหนดค่าดังนั้นฉันจึงเขียนฟังก์ชันชื่อreset_module
ที่ใช้ฟังก์ชั่นimportlib
ของreload
ฟังก์ชั่นและเขียนทับคุณลักษณะทั้งหมดของโมดูลที่ประกาศ มันได้รับการทดสอบด้วย 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
หมายเหตุ:ใช้ด้วยความระมัดระวัง! การใช้สิ่งเหล่านี้กับโมดูลที่ไม่ใช่อุปกรณ์ต่อพ่วง (ตัวอย่างเช่นโมดูลที่กำหนดคลาสที่ใช้ภายนอก) อาจนำไปสู่ปัญหาภายในใน 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 Text ตามรหัสที่sublime_plugin.py
ใช้ในการโหลดโมดูล
ด้านล่างนี้ให้คุณโหลดโมดูลใหม่จากพา ธ ที่มีช่องว่างในชื่อของพวกเขาจากนั้นหลังจากโหลดใหม่คุณสามารถนำเข้าได้ตามปกติ
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
โมดูลจะไม่ได้เก็บขยะเพราะการอ้างอิงระดับโลกที่จัดขึ้นอย่างน้อยใน