私はいくつかの科学データを処理するためのPythonパッケージを開発しています。numpyを含む他のモジュールやパッケージから頻繁に使用されるクラスや関数が複数あり、いずれかで定義されているほぼすべての関数で必要です。パッケージのモジュール。
それらに対処するためのPythonの方法は何でしょうか?私は複数のバリエーションを検討しましたが、それぞれに独自の欠点があります。
_from foreignmodule import Class1, Class2, function1, function2
_を使用してモジュールレベルでクラスをインポートします
インポートされた関数とクラスは、すべての関数から簡単にアクセスできます。一方、モジュールの名前空間を汚染して、dir(package.module)
とhelp(package.module)
をインポートされた関数で乱雑にします
_from foreignmodule import Class1, Class2, function1, function2
_を使用して関数レベルでクラスをインポートします
関数とクラスは簡単にアクセスでき、モジュールを汚染しませんが、すべての関数の最大12個のモジュールからのインポートは、多くの重複コードのように見えます。
_import foreignmodule
_を使用してモジュールレベルでモジュールをインポートします
すべての関数またはクラス呼び出しの前にモジュール名を追加する必要があるため、汚染はそれほど多くありません。
これらすべての操作に関数本体を使用し、エクスポートするオブジェクトのみを返すなど、人為的な回避策を使用してください...このように
_def _export():
from foreignmodule import Class1, Class2, function1, function2
def myfunc(x):
return function1(x, function2(x))
return myfunc
myfunc = _export()
del _export
_
これにより、モジュールの名前空間の汚染と関数の使いやすさの両方の問題をなんとか解決できます...しかし、Pythonicではないようです。
では、最もPythonicなソリューションは何ですか?私が見落とした別の良い解決策はありますか?
先に進み、通常の_from W import X, Y, Z
_を実行してから、___all__
_特殊記号を使用して、モジュールからインポートする実際の記号を定義します。
___all__ = ('MyClass1', 'MyClass2', 'myvar1', …)
_
これは、ユーザーのモジュールから_import *
_の場合に、ユーザーのモジュールにインポートされるシンボルを定義します。
一般に、Pythonプログラマーはnotdir()
を使用してモジュールの使用方法を理解する必要があり、そうしている場合は、ドキュメントを読んだり、help(yourmodule)
と入力してライブラリの使用方法を理解したり、ソースコードを自分で参照したりする必要があります。その場合、(a)インポートするものの違いそして、あなたが定義することは非常に明確であり、(b)彼らは___all__
_宣言を見て、どのおもちゃで遊ぶべきかを知っています。
このような状況で、設計されていないタスクに対してdir()
をサポートしようとすると、他の回答から明らかなように、自分のコードに厄介な制限を課す必要があります。私のアドバイス:それをしないでください!ガイダンスについては、標準ライブラリを参照してください。コードの明快さと簡潔さが必要な場合はいつでも_from … import …
_を実行し、(1)有益なドキュメント文字列、(2)完全なドキュメント、および(3)読み取り可能なコードを提供するため、誰もモジュールでdir()
を実行し、モジュールで実際に定義されているものとは別にインポートを伝えようとする必要があります。
標準ライブラリを含め、私が使用した手法の1つは、import module as _module
またはfrom module import var as _var
を使用することです。つまり、インポートされたモジュール/変数をアンダースコアで始まる名前に割り当てます。
その結果、通常のPython規則に従って、他のコードはそれらのメンバーをプライベートとして扱います。これは、IPythonのオートコンプリート関数など、__all__
を参照しないコードにも適用されます。 。
Python 3.3のrandom
モジュールの例:
from warnings import warn as _warn
from types import MethodType as _MethodType, BuiltinMethodType as _BuiltinMethodType
from math import log as _log, exp as _exp, pi as _pi, e as _e, ceil as _ceil
from math import sqrt as _sqrt, acos as _acos, cos as _cos, sin as _sin
from os import urandom as _urandom
from collections.abc import Set as _Set, Sequence as _Sequence
from hashlib import sha512 as _sha512
もう1つの手法は、関数スコープでインポートを実行して、ローカル変数になるようにすることです。
"""Some module"""
# imports conventionally go here
def some_function(arg):
"Do something with arg."
import re # Regular expressions solve everything
...
これを行う主な理由は、それが事実上怠惰であり、実際に使用されるまでモジュールの依存関係のインポートを遅らせることです。モジュール内の1つの関数が特定の巨大なライブラリに依存していると仮定します。ファイルの先頭にあるライブラリをインポートすると、モジュールをインポートするとライブラリ全体が読み込まれます。このように、モジュールのインポートは迅速に行うことができ、実際にその関数を呼び出すクライアントコードのみが、ライブラリのロードのコストを負担します。さらに、依存関係ライブラリが利用できない場合でも、依存関係機能を必要としないクライアントコードは、モジュールをインポートして他の関数を呼び出すことができます。欠点は、関数レベルのインポートを使用すると、コードの依存関係がわかりにくくなることです。
Python 3.3のos.py
からの例:
def get_exec_path(env=None):
"""[...]"""
# Use a local import instead of a global import to limit the number of
# modules loaded at startup: the os module is always loaded at startup by
# Python. It may also avoid a bootstrap issue.
import warnings
モジュール全体をインポートします:_import foreignmodule
_。あなたが欠点として主張することは、実際には利益です。つまり、モジュール名を前に付けると、コードの保守が容易になり、自己文書化が容易になります。
今から6か月後、foo = Bar(baz)
のようなコード行を見ると、どのモジュールBar
が由来しているかを自問するかもしれませんが、_foo = cleverlib.Bar
_を使用すれば、それはそれほど謎ではありません。
もちろん、インポートが少なければ少ないほど、問題は少なくなります。依存関係がほとんどない小さなプログラムの場合、それはそれほど重要ではありません。
このような質問をしていることに気付いたときは、コードを書きやすくするのではなく、コードを理解しやすくする理由を自問してください。あなたは一度それを書きますが、あなたはそれをたくさん読みます。
この状況では、すべてのファイルが含まれている_all_imports.py
_ファイルを使用します。
_from foreignmodule import .....
from another module import .....
_
次に、作業モジュールで
_import all_imports as fgn # or whatever you want to prepend
...
something = fgn.Class1()
_
注意すべきもう1つのこと
___all__ = ['func1', 'func2', 'this', 'that']
_
これで、モジュール内にあるがnotモジュールの___all__
_にある関数/クラス/変数などはhelp()
に表示されません。 、および_from mymodule import *
_によってインポートされません。詳細については、 Making python imports more structure? を参照してください。
私は妥協して、外部モジュールの短いエイリアスを選択します。
import foreignmodule as fm
それはあなたを汚染(おそらくより大きな問題)から完全に救い、少なくとも前置の負担を減らします。
私はこれが古い質問であることを知っています。 「Pythonic」ではないかもしれませんが、特定のモジュール定義のみをエクスポートするために私が発見した最もクリーンな方法は、実際には、モジュールを関数でグローバルにラップすることです。しかし、それらを返す代わりに、名前をエクスポートするには、単にそれらをグローバル化することができます(グローバルであるため、本質的には一種の「export」キーワードになります)。
def module(): global MyPublicClass、ExportedModule 一部のモジュールをExportedModuleとしてインポート 別のモジュールをPrivateModuleとしてインポート class MyPublicClass: def __init __(self): pass class MyPrivateClass: def __init __(self): pass module() del module
元の結論とそれほど変わらないことはわかっていますが、率直に言って、これが最もクリーンなオプションのようです。もう1つの利点は、この方法で記述されたモジュールをいくつでも1つのファイルにグループ化でき、それらのプライベート用語が重複しないことです。
def module(): グローバルA i、j、k = 1,2,3 クラスA : pass module() del module def module(): グローバルB i、j、k = 7,8,9#以前の宣言を上書きしません クラスB: pass module() del module
ただし、それらのpublic定義は、もちろん重複することに注意してください。