147

PEP 8によると:

  • インポートは、モジュールのコメントとdocstringの直後、モジュールのグローバル変数と定数の前に、常にファイルの先頭に配置されます。

時々、私はPEP 8に違反します。時々、関数内に何かをインポートします。原則として、単一の関数内でのみ使用されるインポートがある場合にこれを行います。

何か意見はありますか?

編集(関数にインポートするのは良い考えだと思う理由):

主な理由:コードをより明確にすることができます。

  • 関数のコードを見ると、「関数/クラスxxxとは何ですか?」と自問するかもしれません。(関数内で使用されているxxx)。モジュールの上部にすべてのインポートがある場合は、そこを調べてxxxが何であるかを判断する必要があります。これは、を使用する場合の問題from m import xxxです。関数を見るm.xxxと、おそらくもっとわかります。何であるかに応じてm:それはよく知られているトップレベルのモジュール/パッケージ(import m)ですか?それともサブモジュール/パッケージ(from a.b.c import m)ですか?
  • 場合によっては、xxxが使用されている場所の近くにその追加情報(「xxxとは何ですか?」)があると、関数が理解しやすくなります。
4

10 に答える 10

108

長期的には、インポートのほとんどをファイルの先頭に配置することで、モジュールがどれほど複雑であるかをインポートする必要があることで一目でわかるようになると思います。

既存のファイルに新しいコードを追加する場合は、通常、必要な場所にインポートを実行します。コードが残っている場合は、インポート行をファイルの先頭に移動することで、より永続的なものにします。

ImportErrorもう1つのポイントは、コードが実行される前に例外を取得することを好みます-健全性チェックとして、それが一番上にインポートするもう1つの理由です。

pyChecker未使用のモジュールをチェックするために使用します。

于 2009-06-22T02:05:00.620 に答える
54

この点で私がPEP8に違反する2つの機会があります。

  • 循環インポート:モジュールAはモジュールBをインポートしますが、モジュールBの何かにモジュールAが必要です(これは、循環依存を排除​​するためにモジュールをリファクタリングする必要があることを示していることがよくあります)
  • pdbブレークポイントの挿入:import pdb; pdb.set_trace()これは便利なb / cですimport pdb。デバッグする可能性のあるすべてのモジュールの先頭に配置したくないので、ブレークポイントを削除するときにインポートを削除することを忘れないでください。

これらの2つのケース以外では、すべてを一番上に置くことをお勧めします。依存関係がより明確になります。

于 2009-06-21T14:53:55.940 に答える
21

これが私たちが使用する4つのインポートのユースケースです

  1. import(およびfrom x import yimport x as y上部に

  2. インポートの選択肢。頂点で。

    import settings
    if setting.something:
        import this as foo
    else:
        import that as foo
    
  3. 条件付きインポート。JSON、XMLライブラリなどで使用されます。頂点で。

    try:
        import this as foo
    except ImportError:
        import that as foo
    
  4. 動的インポート。これまでのところ、この例は1つだけです。

    import settings
    module_stuff = {}
    module= __import__( settings.some_module, module_stuff )
    x = module_stuff['x']
    

    この動的インポートではコードは取り込まれませんが、Pythonで記述された複雑なデータ構造が取り込まれることに注意してください。手で漬け込んだことを除けば、漬け物のようなものです。

    これも、多かれ少なかれ、モジュールの上部にあります


コードを明確にするために行うことは次のとおりです。

  • モジュールは短くしてください。

  • モジュールの上部にすべてのインポートがある場合は、そこを調べて名前を確認する必要があります。モジュールが短い場合、それは簡単です。

  • 場合によっては、名前が使用されている場所の近くにその追加情報があると、関数が理解しやすくなります。モジュールが短い場合、それは簡単です。

于 2009-06-21T15:20:52.283 に答える
10

覚えておくべき1つのこと:不必要なインポートはパフォーマンスの問題を引き起こす可能性があります。したがって、これが頻繁に呼び出される関数である場合は、インポートを一番上に置く方がよいでしょう。もちろん、これ最適化であるため、関数内でのインポートがファイルの先頭でのインポートよりも明確であるという有効なケースがある場合、ほとんどの場合、パフォーマンスよりも優先されます。

IronPythonを実行している場合は、内部関数をインポートする方がよいと言われています(IronPythonでのコードのコンパイルは遅くなる可能性があるため)。したがって、内部関数をインポートする方法を得ることができるかもしれません。しかしそれ以外は、慣習と戦うだけの価値はないと私は主張します。

原則として、単一の関数内でのみ使用されるインポートがある場合にこれを行います。

もう1つ言いたいのは、これは潜在的なメンテナンスの問題である可能性があるということです。以前は1つの関数だけで使用されていたモジュールを使用する関数を追加するとどうなりますか?ファイルの先頭にインポートを追加することを忘れないでください。または、インポートのためにすべての関数をスキャンしますか?

FWIW、関数内にインポートすることが理にかなっている場合があります。たとえば、cx_Oracleで言語を設定する場合は、インポートする_にNLSLANG環境変数を設定する必要があります。したがって、次のようなコードが表示される場合があります。

import os

oracle = None

def InitializeOracle(lang):
    global oracle
    os.environ['NLS_LANG'] = lang
    import cx_Oracle
    oracle = cx_Oracle
于 2009-06-21T15:08:40.280 に答える
6

セルフテストを行うモジュールについては、以前にこのルールに違反しました。つまり、通常はサポートのために使用されますが、メインを定義して、単独で実行した場合に機能をテストできるようにします。getoptその場合、これらのモジュールはモジュールの通常の動作とは関係がなく、テスト用にのみ含まれていることをコードを読んでいる誰かに明確にしたいとcmd思うので、時々インポートしてメインにします。

于 2009-06-21T15:10:58.747 に答える
6

sqlalchemyで使用されている代替アプローチを見てください:依存性注入:

@util.dependencies("sqlalchemy.orm.query")
def merge_result(query, *args):
    #...
    query.Query(...)

インポートされたライブラリがデコレータで宣言され、関数に引数として渡されることに注意してください。

このアプローチにより、コードがよりクリーンになり、ステートメントよりも4.5倍高速に動作します。import

ベンチマーク:https ://gist.github.com/kolypto/589e84fbcfb6312532658df2fabdb796

于 2019-03-26T14:14:40.963 に答える
5

モジュールを2回ロードすることについての質問から来ています-なぜ両方ではないのですか?

スクリプトの上部にあるインポートは、依存関係を示し、関数内の別のインポートにより、この関数がよりアトミックになりますが、連続インポートは安価であるため、パフォーマンスの低下は発生しないようです。

于 2017-09-27T20:43:04.540 に答える
4

まれにしか使用されない関数の内部に役立つ可能性がある別の(おそらく「コーナー」)ケースがあります。それは、import起動時間を短縮することです。

シリアルラインからのコマンドを受け入れて操作を実行する小さなIoTサーバーで実行されるかなり複雑なプログラム、おそらく非常に複雑な操作で、私は一度その壁にぶつかりました。

サーバーの起動前にすべてのimportインポートを処理することを目的としたステートメントをファイルの先頭に配置します。リストには、、、およびその他の「重い重み」が含まれているため(SoCはそれほど強力ではありませんでした)、これは最初の命令が実際に実行される数分前を意味しました。importjinja2lxmlsignxml

OTOHはほとんどのインポートを関数に配置しました。サーバーをシリアルライン上で数秒で「稼働」させることができました。もちろん、モジュールが実際に必要になったとき、私は代償を払わなければなりませんでした(注:これはimport、アイドル時間にsを実行するバックグラウンドタスクを生成することによっても軽減できます)。

于 2020-07-14T15:01:10.883 に答える
3

importそうでない限り、from x import *それらを一番上に置く必要があります。グローバル名前空間に名前を1つだけ追加し、PEP 8に固執します。さらに、後で別の場所で必要になった場合は、何も移動する必要はありません。

大したことではありませんが、ほとんど違いがないので、PEP8の言うことを実行することをお勧めします。

于 2009-06-21T14:44:43.713 に答える
2

両方とも「通常の」モジュールであり、実行できる(つまり、if __name__ == '__main__':セクションがある)モジュールでは、通常、メインセクション内のモジュールを実行するときにのみ使用されるモジュールをインポートします。

例:

def really_useful_function(data):
    ...


def main():
    from pathlib import Path
    from argparse import ArgumentParser
    from dataloader import load_data_from_directory

    parser = ArgumentParser()
    parser.add_argument('directory')
    args = parser.parse_args()
    data = load_data_from_directory(Path(args.directory))
    print(really_useful_function(data)


if __name__ == '__main__':
    main()
于 2019-09-13T06:50:53.973 に答える