web-dev-qa-db-ja.com

内部関数をインポートするのはPythonicですか?

PEP 8 言います:

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

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

意見はありますか?

EDIT(関数をインポートするのが良い考えだと思う理由):

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

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

長い目で見れば、インポートのほとんどがファイルの先頭にあることに感謝すると思います。そうすることで、インポートする必要のあるモジュールがモジュールの複雑さを一目でわかるようになります。

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

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

pyCheckerを使用して、未使用のモジュールを確認します。

73
Peter Ericson

この点でPEP 8に違反する場合が2つあります。

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

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

39
Rick Copeland

使用する4つのインポートユースケースを次に示します

  1. import(およびfrom x import yおよびimport 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で記述された複雑なデータ構造が取り込まれます。手作業で漬け込んだことを除けば、それは一種のデータの漬物のようなものです。

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


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

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

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

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

19
S.Lott

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

IronPythonを使用している場合、関数内にインポートする方が良いと言われています(IronPythonでのコードのコンパイルは遅くなる可能性があるため)。したがって、内部関数をインポートする方法を取得できる場合があります。しかし、それ以外に、私はコンベンションと戦うだけの価値はないと主張します。

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

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

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

import os

Oracle = None

def InitializeOracle(lang):
    global Oracle
    os.environ['NLS_LANG'] = lang
    import cx_Oracle
    Oracle = cx_Oracle
7
Jason Baker

自己テストを行うモジュールについては、この規則を破ったことがあります。つまり、通常はサポートのためだけに使用されますが、それらをメインで定義して、自分で実行した場合に機能をテストできるようにします。その場合、getoptcmdをメインにインポートすることがあります。これは、これらのモジュールがモジュールの通常の動作とは無関係であることをコードを読んでいる人にはっきりさせたいからです。テスト用にのみ含まれています。

6
Daniel Lew

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

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

4
IljaBek

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

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

2
Javier

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

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

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

このアプローチはコードをよりクリーンにし、importステートメントよりも4.5倍速く動作します!

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

2
kolypto