Memuat ulang submodules dalam IPython


363

Saat ini saya sedang mengerjakan proyek python yang berisi sub modul dan menggunakan numpy / scipy. Ipython digunakan sebagai konsol interaktif. Sayangnya saya tidak terlalu senang dengan alur kerja yang saya gunakan saat ini, saya sangat menghargai beberapa saran.

Dalam IPython, framework dimuat oleh importperintah sederhana . Namun, sering kali perlu untuk mengubah kode di salah satu submodules dari framework. Pada titik ini model sudah dimuat dan saya menggunakan IPython untuk berinteraksi dengannya.

Sekarang, kerangka kerja berisi banyak modul yang saling bergantung, yaitu ketika kerangka kerja pertama kali dimuat, modul utama mengimpor dan mengkonfigurasi submodula. Perubahan pada kode hanya dijalankan jika modul dimuat ulang menggunakan reload(main_mod.sub_mod). Ini rumit karena saya perlu memuat ulang semua modul yang diubah secara individual menggunakan path lengkap. Akan sangat nyaman jika reload(main_module)juga memuat ulang semua sub modul, tetapi tanpa memuat ulang numpy / scipy ..


Maukah Anda menguraikan lebih lanjut tentang However, it is often necessary to change code in one of the submodules of the framework.Jadi mengapa necessary to change code? Terima kasih
makan

16
@eat: Kerangka kerja ini terus dikembangkan, jadi ada perubahan konstan pada basis kode.
Alain

Jawaban:


531

IPython hadir dengan beberapa sihir reload otomatis :

%load_ext autoreload
%autoreload 2

Ini akan memuat ulang semua modul yang diubah setiap kali sebelum menjalankan baris baru. Cara kerjanya sedikit berbeda dari dreload. Beberapa peringatan berlaku, ketik %autoreload?untuk melihat apa yang salah.


Jika Anda ingin selalu mengaktifkan pengaturan ini, modifikasi file konfigurasi IPython Anda ~/.ipython/profile_default/ipython_config.py[1] dan tambahkan:

c.InteractiveShellApp.extensions = ['autoreload']     
c.InteractiveShellApp.exec_lines = ['%autoreload 2']

Kredit ke @Kos melalui komentar di bawah ini.

[1] Jika Anda tidak memiliki file ~/.ipython/profile_default/ipython_config.py, Anda harus menelepon ipython profile createdulu. Atau file tersebut dapat ditemukan di $IPYTHONDIR.


63
Saya punya c.InteractiveShellApp.extensions = ['autoreload']dan c.InteractiveShellApp.exec_lines = ['%autoreload 2']di saya ~/.ipython/profile_default/ipython_config.py.
Kos

4
Itu mungkin menjadi hit kinerja, jadi gunakan dengan hati-hati.
penanggung jawab

3
Muat ulang hanya dilakukan ketika Anda menekan Enter di Ipython shell, dan biasanya tidak terlihat.
pv.

3
Ini berfungsi cukup baik ketika men-debug paket, jadi apa tujuan dreload, sepertinya dreload terlalu invasif dan mencetak kesalahan ketika beberapa paket seperti matplotlib dimuat.
dashesy

3
Jika Anda menggunakan metode @Kos, pastikan c didefinisikan: c = get_config ()
Tickon

27

Di IPython 0.12 (dan mungkin sebelumnya), Anda dapat menggunakan ini:

%load_ext autoreload
%autoreload 2

Ini pada dasarnya sama dengan jawaban oleh pv. , kecuali bahwa ekstensi telah diubah namanya dan sekarang dimuat menggunakan %load_ext.


20

Untuk beberapa alasan, tidak ada %autoreload, atau dreloadtampaknya berfungsi untuk situasi ketika Anda mengimpor kode dari satu buku catatan ke yang lain . Hanya Python biasa yang reloadberfungsi:

reload(module)

Berdasarkan [1] .


10
Di Python 3.4+, Anda dapat menemukan ulang di modul importlib. Lihat pertanyaan ini .
Praveen

1
Metode ini berfungsi saat menambahkan metode instan, tidak seperti %autoreloadteknik ini. Ada laporan bug terbuka untuk menambahkan dukungan %autoreloaduntuk ini. .
ijoseph

18

IPython menawarkan dreload()untuk memuat ulang semua submodul secara rekursif. Secara pribadi, saya lebih suka menggunakan %run()perintah ajaib (meskipun tidak melakukan pemuatan ulang yang dalam, seperti yang ditunjukkan oleh John Salvatier dalam komentar).


11
Saya pikir (sayangnya)% run script.py hanya memuat ulang skrip yang Anda panggil, bukan paket yang diimpornya. Jika Anda mencoba men-debug paket yang Anda buat, ini bisa jadi menyebalkan.
John Salvatier

2
NB. dreloadtelah diganti dalam IPython baru-baru ini (misalnya IPython 6.0) dengan deepreload .
dan mackinlay

8

Modul bernama importlibmemungkinkan untuk mengakses impor internal. Terutama, ini menyediakan fungsi importlib.reload():

import importlib
importlib.reload(my_module)

Sebaliknya %autoreload, importlib.reload()atur ulang variabel global yang diatur dalam modul. Dalam kebanyakan kasus, itulah yang Anda inginkan.

importlibhanya tersedia sejak Python 3.1. Untuk versi yang lebih lama, Anda harus menggunakan modul imp.


satu-satunya solusi yang bekerja untuk saya
gustavz

5

http://shawnleezx.github.io/blog/2015/08/03/some-notes-on-ipython-startup-script/

Untuk menghindari pengetikan fungsi ajaib itu berulang-ulang, mereka dapat dimasukkan ke dalam skrip startup ipython (Beri nama dengan .py suffix di bawah .ipython / profile_default / startup. Semua skrip python di bawah folder itu akan dimuat sesuai dengan urutan leksikal), yang terlihat seperti berikut:

from IPython import get_ipython
ipython = get_ipython()

ipython.magic("pylab")
ipython.magic("load_ext autoreload")
ipython.magic("autoreload 2")

Ini juga berfungsi jika Anda menjalankan skrip Anda dengan mis. %run script.pyDari IPython REPL
Patrick Sanan

3

Bagaimana dengan ini:

import inspect

# needs to be primed with an empty set for loaded
def recursively_reload_all_submodules(module, loaded=None):
    for name in dir(module):
        member = getattr(module, name)
        if inspect.ismodule(member) and member not in loaded:
            recursively_reload_all_submodules(member, loaded)
    loaded.add(module)
    reload(module)

import mymodule
recursively_reload_all_submodules(mymodule, set())

Ini harus secara efektif memuat ulang seluruh pohon modul dan submodul yang Anda berikan. Anda juga dapat menempatkan fungsi ini di .ipythonrc Anda (saya pikir) sehingga dimuat setiap kali Anda memulai penerjemah.


Itu terlihat bagus, namun, mungkin itu tidak mencakup modul atau anggota modul yang diimpor menggunakan from ... import ...atau import ... as. Setidaknya itu sering memberi saya masalah ketika bekerja secara interaktif di terminal. Saya telah pindah untuk menggunakan makro yang tersimpan di IPython yang melakukan impor dan pengaturan yang diperlukan untuk mulai bekerja dalam keadaan yang telah ditentukan.
Bernhard

Ini sebenarnya mencakup from ... import ...dan import ... asselama hal yang Anda impor adalah modul. Satu-satunya hal yang tidak tercakup adalah modul dalam paket yang tidak dimuat dari __init__.pyfile itu. Untuk paket, Anda mungkin dapat memeriksa apakah __path__atribut modul adalah direktori. Jika ya, lewati dan impor semua modul yang dapat Anda temukan secara rekursif. Saya tidak menulis bagian ini karena penulis belum meminta solusi untuk paket.
YH Wong

Memang ini terlihat bagus. Saya memikirkan kemungkinan ini, pada saat yang sama saya berharap bahwa akan ada beberapa fungsionalitas bawaan, yaitu berdasarkan ini . Namun, tidak jelas bagi saya bagaimana menggunakan ini. Setelah beberapa penggalian yang seharusnya terjadi sebelum saya memposting pertanyaan asli, saya menemukan ekstensi ini .
Alain

Anda juga dapat menggunakan pkgutiluntuk mendapatkan semua submodul dalam suatu paket, bahkan jika paket tidak mengimpor submodul ke modul teratas. stackoverflow.com/a/1707786/1243926
osa

Anda juga harus melakukan: for module insys.modules:
aoeu256

2

Pilihan lain:

$ cat << EOF > ~/.ipython/profile_default/startup/50-autoreload.ipy
%load_ext autoreload
%autoreload 2
EOF

Diverifikasi pada ipython dan ipython3 v5.1.0 di Ubuntu 14.04.


1

Praktik standar saya untuk memuat ulang adalah menggabungkan kedua metode berikut pembukaan pertama IPython:

from IPython.lib.deepreload import reload
%load_ext autoreload
%autoreload 2

Memuat modul sebelum melakukan ini akan menyebabkan mereka tidak dimuat ulang, bahkan dengan manual reload(module_name). Saya masih, sangat jarang, mendapatkan masalah yang tidak dapat dijelaskan dengan metode kelas yang tidak memuat ulang yang belum saya pelajari.


1

Perhatikan bahwa yang disebutkan di atas autoreloadhanya berfungsi di IntelliJ jika Anda menyimpan file yang diubah secara manual (mis. Menggunakan ctrl + s atau cmd + s). Tampaknya tidak berfungsi dengan hemat otomatis.


Saya mengkonfirmasi ini juga untuk PyCharm.
tsando

0

Di Jupyter Notebooks di Anaconda, lakukan ini:

%load_ext autoreload
%autoreload 2

menghasilkan pesan:

Ekstensi autoreload sudah dimuat. Untuk memuat ulang, gunakan: %reload_ext autoreload

Sepertinya lebih baik dilakukan:

%reload_ext autoreload
%autoreload 2

Informasi versi:

Versi server notebook adalah 5.0.0 dan berjalan pada: Python 3.6.2 | Anaconda, Inc. | (default, 20 Sep 2017, 13:35:58) [MSC v.1900 32 bit (Intel)]


0

Subjek apa pun tidak akan dimuat ulang dengan ini, saya yakin Anda harus menggunakan deepreload IPython untuk itu.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.