Haruskah pernyataan impor selalu di bagian atas modul?

403

PEP 08 menyatakan:

Impor selalu diletakkan di bagian atas file, tepat setelah komentar modul dan dokumen, dan sebelum modul global dan konstanta.

Namun jika kelas / metode / fungsi yang saya impor hanya digunakan dalam kasus yang jarang terjadi, tentunya lebih efisien untuk melakukan impor saat dibutuhkan?

Bukankah ini:

class SomeClass(object):

    def not_often_called(self)
        from datetime import datetime
        self.datetime = datetime.now()

lebih efisien dari ini?

from datetime import datetime

class SomeClass(object):

    def not_often_called(self)
        self.datetime = datetime.now()
Adam J. Forster
sumber

Jawaban:

283

Mengimpor modul cukup cepat, tetapi tidak instan. Ini berarti:

  • Menempatkan impor di bagian atas modul tidak apa-apa, karena itu adalah biaya sepele yang hanya dibayar sekali.
  • Menempatkan impor dalam suatu fungsi akan menyebabkan panggilan ke fungsi tersebut menjadi lebih lama.

Jadi, jika Anda peduli efisiensi, letakkan impor di atas. Hanya pindahkan mereka ke fungsi jika profil Anda menunjukkan itu akan membantu (Anda melakukan profil untuk melihat di mana cara terbaik untuk meningkatkan kinerja, bukan ??)


Alasan terbaik yang saya lihat untuk melakukan impor malas adalah:

  • Dukungan perpustakaan opsional. Jika kode Anda memiliki banyak jalur yang menggunakan pustaka yang berbeda, jangan putus jika pustaka opsional tidak diinstal.
  • Dalam __init__.pyplugin, yang mungkin diimpor tetapi tidak benar-benar digunakan. Contohnya adalah plugin Bazaar, yang menggunakan bzrlibkerangka kerja pemuatan malas.
John Millikin
sumber
17
John, ini adalah pertanyaan yang sepenuhnya teoretis jadi saya tidak memiliki kode untuk profil. Di masa lalu saya selalu mengikuti PEP, tetapi saya menulis beberapa kode hari ini yang membuat saya bertanya-tanya apakah itu hal yang benar untuk dilakukan. Terima kasih atas bantuan Anda.
Adam J. Forster
43
> Menempatkan impor dalam suatu fungsi akan menyebabkan panggilan ke fungsi tersebut menjadi lebih lama. Sebenarnya, saya pikir biaya ini hanya dibayar sekali. Saya telah membaca bahwa Python melakukan cache modul yang diimpor sehingga hanya ada biaya minimal untuk mengimpornya lagi.
moltenform
24
@halfhourhacks Python tidak akan mengimpor kembali modul, tetapi masih harus melakukan beberapa instruksi hanya untuk melihat apakah modul tersebut ada / ada di sys.modules / etc.
John Millikin
24
-1. Menempatkan impor dalam suatu fungsi tidak harus menyebabkannya membutuhkan waktu lebih lama. Silakan lihat jawaban saya pada pertanyaan lain.
aaronasterling
4
Satu use case adalah menghindari impor sirkuler (biasanya tidak masuk akal, tetapi kadang-kadang cocok). Kadang-kadang kelas A dalam modul m1 memanggil metode pada kelas B di modul m2 yang membangun contoh lain dari kelas A. Jika metode di kelas B yang membangun sebuah instance dari kelas A memiliki impor hanya berjalan pada mengeksekusi fungsi yang membangun sebuah instance, impor melingkar dihindari.
Sam Svenbjorgchristiensensen
80

Menempatkan pernyataan impor di dalam suatu fungsi dapat mencegah dependensi melingkar. Misalnya, jika Anda memiliki 2 modul, X.py dan Y.py, dan keduanya harus saling mengimpor, ini akan menyebabkan ketergantungan melingkar ketika Anda mengimpor salah satu modul yang menyebabkan loop tak terbatas. Jika Anda memindahkan pernyataan impor di salah satu modul, maka ia tidak akan mencoba mengimpor modul lain hingga fungsinya dipanggil, dan modul itu sudah akan diimpor, jadi tidak ada loop tanpa batas. Baca di sini untuk lebih lanjut - effbot.org/zone/import-confusion.htm

Moe
sumber
3
Ya tapi seseorang bisa masuk neraka ketergantungan.
eigenein
8
Jika dua modul perlu saling mengimpor, ada sesuatu yang salah dengan kode tersebut.
Anna
Pemrograman berorientasi objek sering membawa saya ke dependensi melingkar. Kelas objek vital dapat diimpor ke beberapa modul. Agar objek ini dapat melakukan tugasnya sendiri, mungkin perlu menjangkau satu atau lebih dari modul tersebut. Ada cara untuk menghindarinya, seperti mengirim data ke objek melalui fungsi args, untuk memungkinkannya mengakses modul lain. Tetapi ada kalanya melakukan hal ini terasa sangat berlawanan dengan intuisi untuk OOP (dunia luar tidak perlu tahu bagaimana menyelesaikan tugas dalam fungsi itu).
Robert
4
Ketika X membutuhkan Y dan Y membutuhkan X, mereka adalah dua bagian dari ide yang sama (yaitu harus didefinisikan bersama) atau ada abstraksi yang hilang.
GLRoman
59

Saya telah mengadopsi praktik meletakkan semua impor dalam fungsi yang menggunakannya, bukan di bagian atas modul.

Manfaat yang saya dapatkan adalah kemampuan untuk refactor lebih andal. Ketika saya memindahkan fungsi dari satu modul ke modul lainnya, saya tahu bahwa fungsi tersebut akan terus bekerja dengan semua warisan pengujian yang masih ada. Jika saya memiliki impor saya di bagian atas modul, ketika saya memindahkan fungsi, saya menemukan bahwa saya menghabiskan banyak waktu untuk mendapatkan impor modul baru yang lengkap dan minimal. IDE refactoring mungkin membuat ini tidak relevan.

Ada penalti kecepatan seperti yang disebutkan di tempat lain. Saya telah mengukur ini dalam aplikasi saya dan ternyata tidak signifikan untuk tujuan saya.

Ini juga bagus untuk dapat melihat semua dependensi modul di depan tanpa menggunakan pencarian (misalnya grep). Namun, alasan saya peduli dengan dependensi modul umumnya karena saya menginstal, refactoring, atau memindahkan seluruh sistem yang terdiri dari beberapa file, bukan hanya satu modul. Dalam hal ini, saya akan tetap melakukan pencarian global untuk memastikan saya memiliki dependensi tingkat sistem. Jadi saya belum menemukan impor global untuk membantu pemahaman saya tentang suatu sistem dalam praktiknya.

Saya biasanya memasukkan impor sysdi dalam if __name__=='__main__'cek dan kemudian meneruskan argumen (seperti sys.argv[1:]) ke suatu main()fungsi. Ini memungkinkan saya untuk menggunakan maindalam konteks di mana sysbelum diimpor.


sumber
4
Banyak IDE mudah melakukan refactoring kode dengan mengoptimalkan dan mengimpor modul yang diperlukan secara otomatis ke file Anda untuk Anda. Dalam sebagian besar kasus, PyCharm dan Eclipse telah membuat keputusan yang tepat untuk saya. Saya berani bertaruh ada cara untuk mendapatkan perilaku yang sama dalam emacs atau vim.
brent.payne
3
Impor di dalam pernyataan if di namespace global masih merupakan impor global. Ini akan mencetak argumen (menggunakan Python 3): def main(): print(sys.argv); if True: import sys; main();Anda harus membungkus if __name__=='__main__'fungsi untuk membuat namespace baru.
Darcinon
4
Ini menurut saya sebagai alasan yang sangat baik untuk mengimpor dalam fungsi daripada dalam lingkup global. Saya cukup terkejut tidak ada orang lain yang mengatakan melakukannya karena alasan yang sama. Apakah ada kelemahan yang signifikan, selain kinerja dan verbositas?
algal
@ Algal downside adalah bahwa banyak orang python membenci ini karena Anda melanggar naskah kuno. Anda harus meyakinkan anggota tim Anda. Penalti kinerja minimal. Terkadang bahkan lebih cepat, lihat stackoverflow.com/a/4789963/362951
mit
Saya merasa sangat berguna untuk refactoring menempatkan impor dekat dengan tempat saya menggunakannya. Tidak perlu lagi menggulir ke atas dan belakang begitu banyak tim. Saya menggunakan IDE seperti pycharm atau sayap ide dan juga menggunakan refactoring mereka, tetapi saya tidak selalu ingin bergantung pada mereka. Memindahkan fungsi ke modul lain menjadi jauh lebih mudah dengan gaya impor alternatif ini, sebagai akibatnya saya jauh lebih refactor.
mit
39

Sebagian besar waktu ini akan berguna untuk kejelasan dan masuk akal untuk dilakukan tetapi tidak selalu demikian. Berikut adalah beberapa contoh keadaan di mana impor modul mungkin tinggal di tempat lain.

Pertama, Anda bisa memiliki modul dengan unit test formulir:

if __name__ == '__main__':
    import foo
    aa = foo.xyz()         # initiate something for the test

Kedua, Anda mungkin memiliki persyaratan untuk mengimpor beberapa modul yang berbeda saat runtime.

if [condition]:
    import foo as plugin_api
else:
    import bar as plugin_api
xx = plugin_api.Plugin()
[...]

Mungkin ada situasi lain di mana Anda dapat menempatkan impor di bagian lain dalam kode.

ConcernedOfTunbridgeWells
sumber
14

Varian pertama memang lebih efisien daripada yang kedua ketika fungsinya disebut nol atau satu kali. Dengan doa kedua dan selanjutnya, pendekatan "impor setiap panggilan" sebenarnya kurang efisien. Lihat tautan ini untuk teknik pemuatan malas yang menggabungkan yang terbaik dari kedua pendekatan dengan melakukan "impor malas".

Tetapi ada alasan lain selain efisiensi mengapa Anda lebih suka yang satu daripada yang lain. Salah satu pendekatan adalah membuatnya lebih jelas bagi seseorang yang membaca kode tentang dependensi yang dimiliki modul ini. Mereka juga memiliki karakteristik kegagalan yang sangat berbeda - yang pertama akan gagal pada waktu pengambilan jika tidak ada modul "datetime" sementara yang kedua tidak akan gagal sampai metode dipanggil.

Catatan yang ditambahkan: Di IronPython, impor bisa sedikit lebih mahal daripada di CPython karena kode pada dasarnya sedang dikompilasi karena sedang diimpor.

Curt Hagenlocher
sumber
1
Tidak benar bahwa yang pertama berkinerja lebih baik: wiki.python.org/moin/PythonSpeed/…
Jason Baker
Berkinerja lebih baik jika metode ini tidak pernah dipanggil karena impor tidak pernah terjadi.
Curt Hagenlocher
Benar, tetapi kinerjanya lebih buruk jika metode ini dipanggil lebih dari sekali. Dan manfaat kinerja yang akan Anda peroleh dari tidak mengimpor modul segera diabaikan dalam banyak kasus. Pengecualiannya adalah jika modulnya sangat besar atau ada banyak fungsi seperti ini.
Jason Baker
Di dunia IronPython, impor awal jauh lebih mahal daripada di CPython;). Contoh "impor malas" di tautan Anda mungkin adalah solusi umum terbaik secara keseluruhan.
Curt Hagenlocher
Saya harap Anda tidak keberatan, tetapi saya mengeditnya di posting Anda. Itu informasi yang berguna untuk diketahui.
Jason Baker
9

Curt membuat poin yang bagus: versi kedua lebih jelas dan akan gagal pada waktu buka daripada nanti, dan secara tak terduga.

Biasanya saya tidak khawatir tentang efisiensi memuat modul, karena itu (a) cukup cepat, dan (b) kebanyakan hanya terjadi saat startup.

Jika Anda harus memuat modul kelas berat pada waktu yang tidak terduga, mungkin lebih masuk akal untuk memuatnya secara dinamis dengan __import__fungsi tersebut, dan pastikan untuk menangkap ImportErrorpengecualian, dan menanganinya dengan cara yang masuk akal.

Dan Lenski
sumber
8

Saya tidak akan khawatir tentang efisiensi memuat modul di depan terlalu banyak. Memori yang diambil oleh modul tidak akan terlalu besar (dengan asumsi itu cukup modular) dan biaya awal akan diabaikan.

Dalam kebanyakan kasus, Anda ingin memuat modul di bagian atas file sumber. Untuk seseorang yang membaca kode Anda, akan lebih mudah untuk mengetahui fungsi atau objek apa yang berasal dari modul apa.

Salah satu alasan bagus untuk mengimpor modul di tempat lain dalam kode adalah jika itu digunakan dalam pernyataan debugging.

Sebagai contoh:

do_something_with_x(x)

Saya bisa men-debug ini dengan:

from pprint import pprint
pprint(x)
do_something_with_x(x)

Tentu saja, alasan lain untuk mengimpor modul di tempat lain dalam kode adalah jika Anda perlu mengimpornya secara dinamis. Ini karena Anda hampir tidak punya pilihan.

Saya tidak akan khawatir tentang efisiensi memuat modul di depan terlalu banyak. Memori yang diambil oleh modul tidak akan terlalu besar (dengan asumsi itu cukup modular) dan biaya awal akan diabaikan.

Jason Baker
sumber
Kita berbicara tentang puluhan milidetik biaya startup per modul (di komputer saya). Itu tidak selalu dapat diabaikan, misalnya jika itu memengaruhi respons suatu aplikasi web terhadap klik pengguna.
Evgeni Sergeev
6

Ini merupakan tradeoff, yang hanya dapat diputuskan oleh programmer.

Kasus 1 menghemat sebagian memori dan waktu startup dengan tidak mengimpor modul datetime (dan melakukan inisialisasi apa pun yang diperlukan) hingga diperlukan. Perhatikan bahwa melakukan impor 'hanya ketika dipanggil' juga berarti melakukannya 'setiap kali ketika dipanggil', sehingga setiap panggilan setelah yang pertama masih menimbulkan biaya tambahan tambahan untuk melakukan impor.

Kasus 2 menghemat waktu pelaksanaan dan latensi dengan mengimpor datetime sebelumnya sehingga not_often_called () akan kembali lebih cepat ketika sedang disebut, dan juga dengan tidak menimbulkan biaya overhead impor pada setiap panggilan.

Selain efisiensi, lebih mudah untuk melihat dependensi modul di depan jika pernyataan impor ... di depan. Menyembunyikannya dalam kode dapat membuatnya lebih sulit untuk dengan mudah menemukan modul apa yang menjadi sandarannya.

Secara pribadi saya biasanya mengikuti PEP kecuali untuk hal-hal seperti tes unit dan sehingga saya tidak ingin selalu dimuat karena saya tahu mereka tidak akan digunakan kecuali untuk kode tes.

pjz
sumber
2
-1. Biaya impor utama hanya terjadi pertama kali. Biaya mencari modul sys.modulesdengan mudah dapat diimbangi dengan penghematan hanya dengan harus mencari nama lokal, bukan nama global.
aaronasterling
6

Berikut adalah contoh di mana semua impor berada di bagian paling atas (ini adalah satu-satunya waktu saya perlu melakukan ini) Saya ingin dapat menghentikan subproses pada Un * x dan Windows.

import os
# ...
try:
    kill = os.kill  # will raise AttributeError on Windows
    from signal import SIGTERM
    def terminate(process):
        kill(process.pid, SIGTERM)
except (AttributeError, ImportError):
    try:
        from win32api import TerminateProcess  # use win32api if available
        def terminate(process):
            TerminateProcess(int(process._handle), -1)
    except ImportError:
        def terminate(process):
            raise NotImplementedError  # define a dummy function

(Pada ulasan: apa yang dikatakan John Millikin .)

Giltay
sumber
6

Ini seperti banyak optimasi lainnya - Anda mengorbankan keterbacaan untuk kecepatan. Seperti yang disebutkan oleh John, jika Anda telah melakukan pekerjaan rumah profil Anda dan menemukan ini sebagai perubahan yang cukup bermanfaat dan Anda membutuhkan kecepatan ekstra, maka lakukanlah. Mungkin baik untuk mencatat dengan semua impor lainnya:

from foo import bar
from baz import qux
# Note: datetime is imported in SomeClass below
Drew Stephens
sumber
4

Inisialisasi modul hanya terjadi sekali - pada impor pertama. Jika modul yang dimaksud adalah dari pustaka standar, maka Anda kemungkinan akan mengimpornya dari modul lain di program Anda juga. Untuk sebuah modul yang lazim seperti masa-masa, itu juga kemungkinan merupakan ketergantungan bagi banyak perpustakaan standar lainnya. Pernyataan impor akan menelan biaya sangat sedikit karena sejak modul akan terjadi sudah terjadi. Semua yang dilakukannya saat ini adalah mengikat objek modul yang ada ke lingkup lokal.

Pasangan informasi itu dengan argumen untuk keterbacaan dan saya akan mengatakan bahwa yang terbaik adalah memiliki pernyataan impor pada ruang lingkup modul.

Jeremy Brown
sumber
4

Hanya untuk melengkapi jawaban Moe dan pertanyaan aslinya:

Ketika kita harus berurusan dengan ketergantungan sirkuler kita dapat melakukan beberapa "trik". Dengan asumsi kami bekerja dengan modul a.pydan b.pyyang berisi x()dan b y(), masing-masing. Kemudian:

  1. Kita dapat memindahkan salah satu from importsdi bagian bawah modul.
  2. Kami dapat memindahkan salah satu dari from importsdalam fungsi atau metode yang sebenarnya membutuhkan impor (ini tidak selalu mungkin, karena Anda dapat menggunakannya dari beberapa tempat).
  3. Kami dapat mengubah salah satu dari keduanya from importsmenjadi impor yang terlihat seperti:import a

Jadi, untuk menyimpulkan. Jika Anda tidak berurusan dengan dependensi melingkar dan melakukan semacam trik untuk menghindarinya, maka lebih baik untuk meletakkan semua impor Anda di atas karena alasan yang sudah dijelaskan dalam jawaban lain untuk pertanyaan ini. Dan tolong, ketika melakukan "trik" ini termasuk komentar, itu selalu diterima! :)

Caumons
sumber
4

Selain jawaban luar biasa yang telah diberikan, perlu dicatat bahwa penempatan impor bukan hanya masalah gaya. Kadang-kadang modul memiliki dependensi implisit yang perlu diimpor atau diinisialisasi terlebih dahulu, dan impor tingkat atas dapat menyebabkan pelanggaran terhadap urutan eksekusi yang diperlukan.

Masalah ini sering muncul di API Python Apache Spark, di mana Anda perlu menginisialisasi SparkContext sebelum mengimpor paket atau modul pyspark. Yang terbaik adalah menempatkan impor pyspark dalam cakupan di mana SparkContext dijamin akan tersedia.

Paul
sumber
4

Saya terkejut tidak melihat angka biaya aktual untuk pemeriksaan beban berulang yang sudah diposting, meskipun ada banyak penjelasan bagus tentang apa yang diharapkan.

Jika Anda mengimpor di bagian atas, Anda menerima pukulan apa pun yang terjadi. Itu cukup kecil, tetapi biasanya dalam milidetik, bukan nanodetik.

Jika Anda mengimpor dalam suatu fungsi, maka Anda hanya menerima klik untuk memuat jika dan ketika salah satu dari fungsi tersebut pertama kali dipanggil. Seperti yang telah ditunjukkan banyak orang, jika itu tidak terjadi sama sekali, Anda menghemat waktu muat. Tetapi jika fungsi dipanggil banyak, Anda mengambil hit berulang meskipun jauh lebih kecil (untuk memeriksa bahwa itu telah dimuat; bukan untuk benar-benar memuat ulang). Di sisi lain, seperti yang ditunjukkan @aaronasterling, Anda juga sedikit menghemat karena mengimpor dalam suatu fungsi memungkinkan fungsi menggunakan pencarian variabel lokal yang sedikit lebih cepat untuk mengidentifikasi nama nanti ( http://stackoverflow.com/questions/477096/python- import-coding-style / 4789963 # 4789963 )

Berikut ini adalah hasil dari tes sederhana yang mengimpor beberapa hal dari dalam suatu fungsi. Waktu yang dilaporkan (dalam Python 2.7.14 pada 2.3 GHz Intel Core i7) ditunjukkan di bawah ini (panggilan ke-2 yang mengambil lebih banyak dari panggilan-panggilan selanjutnya tampaknya konsisten, meskipun saya tidak tahu mengapa).

 0 foo:   14429.0924 µs
 1 foo:      63.8962 µs
 2 foo:      10.0136 µs
 3 foo:       7.1526 µs
 4 foo:       7.8678 µs
 0 bar:       9.0599 µs
 1 bar:       6.9141 µs
 2 bar:       7.1526 µs
 3 bar:       7.8678 µs
 4 bar:       7.1526 µs

Kode:

from __future__ import print_function
from time import time

def foo():
    import collections
    import re
    import string
    import math
    import subprocess
    return

def bar():
    import collections
    import re
    import string
    import math
    import subprocess
    return

t0 = time()
for i in xrange(5):
    foo()
    t1 = time()
    print("    %2d foo: %12.4f \xC2\xB5s" % (i, (t1-t0)*1E6))
    t0 = t1
for i in xrange(5):
    bar()
    t1 = time()
    print("    %2d bar: %12.4f \xC2\xB5s" % (i, (t1-t0)*1E6))
    t0 = t1
TextGeek
sumber
Perubahan runtime kemungkinan disebabkan oleh penskalaan frekuensi CPU sebagai respons terhadap beban. Lebih baik memulai tes kecepatan dengan pekerjaan sibuk yang kedua untuk meningkatkan kecepatan jam CPU.
Han-Kwang Nienhuys
3

Saya tidak bercita-cita untuk memberikan jawaban yang lengkap, karena orang lain telah melakukan ini dengan sangat baik. Saya hanya ingin menyebutkan satu use case ketika saya menemukan sangat berguna untuk mengimpor modul di dalam fungsi. Aplikasi saya menggunakan paket python dan modul yang disimpan di lokasi tertentu sebagai plugin. Selama startup aplikasi, aplikasi berjalan melalui semua modul di lokasi dan mengimpornya, kemudian melihat ke dalam modul dan jika menemukan beberapa titik pemasangan untuk plugin (dalam kasus saya itu adalah subkelas dari kelas dasar tertentu yang memiliki unik ID) itu mendaftarkan mereka. Jumlah plugin besar (sekarang puluhan, tapi mungkin ratusan di masa depan) dan masing-masing jarang digunakan. Memiliki impor perpustakaan pihak ketiga di bagian atas modul plugin saya adalah penalti sedikit selama startup aplikasi. Terutama beberapa perpustakaan pihak ketiga yang berat untuk diimpor (mis. Impor plotly bahkan mencoba untuk terhubung ke internet dan mengunduh sesuatu yang menambahkan sekitar satu detik untuk startup). Dengan mengoptimalkan impor (memanggil mereka hanya dalam fungsi di mana mereka digunakan) di plugin saya berhasil mengecilkan startup dari 10 detik menjadi sekitar 2 detik. Itu adalah perbedaan besar bagi pengguna saya.

Jadi jawaban saya adalah tidak, jangan selalu meletakkan impor di bagian atas modul Anda.

VK
sumber
3

Sangat menarik bahwa tidak ada satu jawaban yang menyebutkan pemrosesan paralel sejauh ini, di mana mungkin DIBUTUHKAN bahwa impor ada dalam fungsi, ketika kode fungsi serial adalah apa yang didorong ke inti lainnya, misalnya seperti dalam kasus ipyparallel.

K.-Michael Aye
sumber
1

Mungkin ada peningkatan kinerja dengan mengimpor variabel / pelingkupan lokal di dalam suatu fungsi. Ini tergantung pada penggunaan barang yang diimpor di dalam fungsi. Jika Anda mengulang berulang kali dan mengakses objek global modul, mengimpornya sebagai lokal dapat membantu.

test.py

X=10
Y=11
Z=12
def add(i):
  i = i + 10

runlocal.py

from test import add, X, Y, Z

    def callme():
      x=X
      y=Y
      z=Z
      ladd=add 
      for i  in range(100000000):
        ladd(i)
        x+y+z

    callme()

run.py

from test import add, X, Y, Z

def callme():
  for i in range(100000000):
    add(i)
    X+Y+Z

callme()

Waktu di Linux menunjukkan keuntungan kecil

/usr/bin/time -f "\t%E real,\t%U user,\t%S sys" python run.py 
    0:17.80 real,   17.77 user, 0.01 sys
/tmp/test$ /usr/bin/time -f "\t%E real,\t%U user,\t%S sys" python runlocal.py 
    0:14.23 real,   14.22 user, 0.01 sys

sebenarnya adalah jam dinding. pengguna adalah waktu dalam program. sys adalah waktu untuk panggilan sistem.

https://docs.python.org/3.5/reference/executionmodel.html#resolution-of-names

quiet_penguin
sumber
1

Keterbacaan

Selain kinerja startup, ada argumen keterbacaan yang dibuat untuk melokalkan importpernyataan. Misalnya, ambil nomor baris python 1283 hingga 1296 dalam proyek python pertama saya saat ini:

listdata.append(['tk font version', font_version])
listdata.append(['Gtk version', str(Gtk.get_major_version())+"."+
                 str(Gtk.get_minor_version())+"."+
                 str(Gtk.get_micro_version())])

import xml.etree.ElementTree as ET

xmltree = ET.parse('/usr/share/gnome/gnome-version.xml')
xmlroot = xmltree.getroot()
result = []
for child in xmlroot:
    result.append(child.text)
listdata.append(['Gnome version', result[0]+"."+result[1]+"."+
                 result[2]+" "+result[3]])

Jika importpernyataan itu ada di bagian atas file saya harus gulir ke atas, atau tekan Home, untuk mencari tahu apa ETitu. Maka saya harus menavigasi kembali ke baris 1283 untuk melanjutkan membaca kode.

Memang, bahkan jika importpernyataan itu di atas fungsi (atau kelas) karena banyak yang akan menempatkannya, paging naik dan turun akan diperlukan.

Menampilkan nomor versi Gnome jarang akan dilakukan sehingga bagian importatas file memperkenalkan jeda startup yang tidak perlu.

WinEunuuchs2Unix
sumber
0

Saya ingin menyebutkan usecase milik saya, sangat mirip dengan yang disebutkan oleh @John Millikin dan @VK:

Impor Opsional

Saya melakukan analisis data dengan Jupyter Notebook, dan saya menggunakan notebook IPython yang sama sebagai templat untuk semua analisis. Dalam beberapa kesempatan, saya perlu mengimpor Tensorflow untuk melakukan beberapa model cepat, tetapi kadang-kadang saya bekerja di tempat-tempat di mana tensorflow tidak diatur / lambat untuk diimpor. Dalam kasus tersebut, saya merangkum operasi Tensorflow saya yang bergantung pada fungsi pembantu, mengimpor tensorflow di dalam fungsi itu, dan mengikatnya ke tombol.

Dengan cara ini, saya bisa melakukan "restart-and-run-all" tanpa harus menunggu impor, atau harus melanjutkan sisa sel ketika gagal.

Cedar
sumber
0

Ini adalah diskusi yang menarik. Seperti banyak orang lain, saya bahkan tidak pernah mempertimbangkan topik ini. Saya terpojok karena harus mengimpor fungsi karena ingin menggunakan ORANG Django di salah satu perpustakaan saya. Saya harus menelepon django.setup()sebelum mengimpor kelas model saya dan karena ini di bagian atas file itu sedang diseret ke dalam kode perpustakaan sepenuhnya non-Django karena konstruksi injektor IoC.

Saya agak meretas sekitar dan akhirnya menempatkan django.setup()di konstruktor singleton dan impor yang relevan di bagian atas setiap metode kelas. Sekarang ini berfungsi dengan baik tetapi membuat saya gelisah karena impor tidak di atas dan saya juga mulai khawatir tentang tambahan waktu impor. Lalu saya datang ke sini dan membaca dengan penuh minat semua orang mengambil ini.

Saya memiliki latar belakang C ++ yang panjang dan sekarang menggunakan Python / Cython. Menurut saya ini adalah mengapa tidak menempatkan impor dalam fungsi kecuali itu menyebabkan Anda mengalami kemacetan yang diprofilkan. Ini hanya seperti mendeklarasikan ruang untuk variabel sebelum Anda membutuhkannya. Masalahnya adalah saya memiliki ribuan baris kode dengan semua impor di atas! Jadi saya pikir saya akan melakukannya mulai sekarang dan mengubah file aneh di sana-sini ketika saya melewati dan punya waktu.

LJHW
sumber