นำเข้าโมดูลอีกครั้งในหลามในขณะที่โต้ตอบ


382

ฉันรู้ว่ามันสามารถทำได้ แต่ฉันไม่เคยจำได้ว่า

คุณจะนำเข้าโมดูลอีกครั้งในไพ ธ อนได้อย่างไร สถานการณ์เป็นดังนี้: ฉันนำเข้าโมดูลแบบโต้ตอบและคนจรจัดกับมัน แต่แล้วฉันก็พบข้อผิดพลาด ฉันแก้ไขข้อผิดพลาดในไฟล์. py จากนั้นฉันต้องการนำเข้าโมดูลถาวรอีกครั้งโดยไม่ต้องปิด python ฉันจะทำมันได้อย่างไร



คำตอบ:


368

สิ่งนี้น่าจะใช้ได้:

reload(my.module)

จากPython docs

โหลดโมดูลที่นำเข้าก่อนหน้านี้อีกครั้ง อาร์กิวเมนต์ต้องเป็นวัตถุโมดูลดังนั้นจึงต้องนำเข้าสำเร็จก่อน สิ่งนี้มีประโยชน์หากคุณแก้ไขไฟล์ซอร์สโมดูลโดยใช้เอดิเตอร์ภายนอกและต้องการลองใช้เวอร์ชันใหม่โดยไม่ต้องใช้ Python interpreter

ถ้าทำงานหลาม 3.4 และขึ้นไม่แล้วทำimport importlibimportlib.reload(nameOfModule)

อย่าลืมคำเตือนในการใช้วิธีนี้:

  • เมื่อโมดูลถูกโหลดใหม่พจนานุกรมของมัน (ที่มีตัวแปรส่วนกลางของโมดูล) จะถูกเก็บไว้ การกำหนดชื่อใหม่จะแทนที่คำจำกัดความเก่าดังนั้นโดยทั่วไปจะไม่เกิดปัญหา แต่หากเวอร์ชันใหม่ของโมดูลไม่ได้กำหนดชื่อที่กำหนดโดยเวอร์ชันเก่านิยามเก่าจะไม่ถูกลบออก

  • หากโมดูลนำเข้าวัตถุจากโมดูลอื่นที่ใช้การfrom ... import ...เรียกreload()ใช้โมดูลอื่นไม่ได้กำหนดวัตถุที่นำเข้าจากมันอีกวิธีหนึ่งคือดำเนินการfromคำสั่งอีกครั้งอีกครั้งคือการใช้importและชื่อที่ผ่านการรับรอง ( module.*name*) แทน

  • หากโมดูลอินสแตนซ์ของคลาสเป็นอินสแตนซ์ของการโหลดโมดูลที่กำหนดคลาสจะไม่ส่งผลกระทบต่อการกำหนดวิธีการของอินสแตนซ์ - พวกเขายังคงใช้คำนิยามคลาสเก่า เช่นเดียวกับคลาสที่ได้รับ


26
from filename import *ถ้าผมโหลดโมดูลของฉันโดยใช้ จะโหลดซ้ำได้อย่างไร
Peter Zhu

@PeterZhu สำหรับกรณี "from mod import fcn" วัตถุโมดูลจะไม่ถูกเพิ่มไปยังพื้นที่ชื่อ ดังนั้นคุณต้องนำเข้าโมดูลอย่างชัดเจนดังนั้นคุณสามารถโหลดซ้ำได้ในภายหลัง import foo; from foo import bar; reload(foo)
Ted

ฉันลองโหลดซ้ำเช่นเดียวกับเวทมนต์โหลดอัตโนมัติและฉันเห็นการเปลี่ยนแปลงรหัสของฉันสะท้อนในสแต็กของข้อความแสดงข้อผิดพลาด แต่ข้อผิดพลาดตัวเองยังคงปรากฏอยู่เพื่อปิดรหัสค้าง (เช่นบรรทัดของข้อผิดพลาดจะเหมือนกันแน่นอน บรรทัดเหมือนก่อนซึ่งฉันได้เปลี่ยนเป็นความคิดเห็นและความคิดเห็นอย่างชัดเจนไม่สามารถทำให้เกิดข้อผิดพลาด) โมดูลของฉันถูกโหลดเป็นส่วนขยาย Jupyter ทุกคนอาจรู้ว่าสิ่งนี้ต้องใช้งานที่แตกต่างกันไปรอบ ๆ ? ขอบคุณ!
yifanwu

1
หากคุณนำเข้าฟังก์ชั่นของคุณดังต่อไปนี้ "mod นำเข้าเป็นชื่อ" จากนั้นคุณต้องทำดังนี้ 'นำเข้า importlib importlib.reload (ชื่อ)'
Noe

วิธีนี้อาจไม่แทนที่การอ้างอิงโมดูลอื่น ๆ ไปยังโมดูลโหลดใหม่ ดูstackoverflow.com/a/61617169/2642356สำหรับวิธีแก้ไข
EZLearner

287

ใน python 3 reloadจะไม่มีฟังก์ชันในตัวอีกต่อไป

ถ้าคุณใช้ python 3.4+ คุณควรใช้reloadจากไลบรารี่importlibแทน:

import importlib
importlib.reload(some_module)

หากคุณใช้ python 3.2 หรือ 3.3 คุณควร:

import imp  
imp.reload(module)  

แทน. โปรดดูhttp://docs.python.org/3.0/library/imp.html#imp.reload

หากคุณใช้งานipythonให้พิจารณาใช้autoreloadส่วนขยายอย่างแน่นอน:

%load_ext autoreload
%autoreload 2

ถึงแม้ว่ารหัส Python จำนวนมากจะถูกเขียนใน Python 2 แต่ Python 3 จะกลายเป็นตัวเลือกที่ทำงานได้มากขึ้นทุกวัน ขอบคุณสำหรับทิป!
แอรอนจอห์นสัน

40
imp.reloadเลิกใช้แล้วตั้งแต่ Python 3.4 ใช้importlib.reloadฟังก์ชั่นแทน
jfs

1
@ แอนดรีขอบคุณ! ฉันใช้โหลดอัตโนมัติ% มันยอดเยี่ยมวัตถุที่สร้างขึ้นแล้วของฉันได้รับการแก้ไขวิธีการเรียนโดยอัตโนมัติโดยไม่ต้องสร้างใหม่อีกครั้ง
jeanmi

4
ฉันบิตปลาย แต่ฉันคิดว่านี่ไม่ทำงานถ้าสิ่งที่คุณต้องโหลดเป็นฟังก์ชั่นหรือระดับจากภายในโมดูล: ถ้างบนำเข้าของฉันคือfrom mymodule import myfuncแล้วimportlib.reload(myfunc), importlib.reload(mymodule.myfunc), importlib.reload(mymodule)ทั้งหมดให้ NameError
Puff

@Puff ดูคำตอบของฉันด้านล่างสำหรับวิธีการนำเข้าฟังก์ชั่นอีกครั้ง
jss367

46

ที่จริงแล้วใน Python 3 โมดูลimpจะถูกทำเครื่องหมายว่าเลิกใช้แล้ว อย่างน้อยก็เป็นจริงสำหรับ 3.4

ควรใช้reloadฟังก์ชันจากimportlibโมดูลแทน:

https://docs.python.org/3/library/importlib.html#importlib.reload

แต่โปรดทราบว่าห้องสมุดนี้มีการเปลี่ยนแปลง API บางอย่างกับรุ่นรองสองรุ่นล่าสุด


6

ถ้าคุณต้องการนำเข้าฟังก์ชั่นหรือคลาสที่เฉพาะเจาะจงจากโมดูลคุณสามารถทำได้:

import importlib
import sys
importlib.reload(sys.modules['my_module'])
from my_module import my_function

0

แม้ว่าคำตอบที่ให้ไว้จะใช้ได้กับโมดูลที่เฉพาะเจาะจง แต่ก็จะไม่โหลด submodules ดังที่ระบุไว้ในคำตอบนี้ :

หากโมดูลนำเข้าวัตถุจากโมดูลอื่นที่ใช้การfrom ... import ...เรียกreload()ใช้โมดูลอื่นไม่ได้กำหนดวัตถุที่นำเข้าจากมันอีกวิธีหนึ่งคือดำเนินการคำสั่งจากคำสั่งอีกครั้งหนึ่งคือการใช้importและชื่อที่ผ่านการรับรอง ( module.*name*) แทน

อย่างไรก็ตามหากใช้__all__ตัวแปรเพื่อกำหนด API สาธารณะมันเป็นไปได้ที่จะทำการโหลดโมดูลที่มีอยู่ทั้งหมดโดยอัตโนมัติ:

# Python >= 3.5
import importlib
import types


def walk_reload(module: types.ModuleType) -> None:
    if hasattr(module, "__all__"):
        for submodule_name in module.__all__:
            walk_reload(getattr(module, submodule_name))
    importlib.reload(module)


walk_reload(my_module)

คำเตือนที่ระบุไว้ในคำตอบก่อนหน้านี้ยังคงใช้ได้แม้ว่า ยวดการแก้ไข submodule ที่ไม่ได้เป็นส่วนหนึ่งของ API สาธารณะตามที่อธิบายโดย__all__ตัวแปรจะไม่ได้รับผลกระทบจากการโหลดซ้ำโดยใช้ฟังก์ชั่นนี้ ในทำนองเดียวกันการลบองค์ประกอบของ submodule จะไม่ส่งผลต่อการโหลดซ้ำ

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.