import module
使用するのが最適かどうかについての包括的なガイドを見つけようとしましたfrom module import
。Pythonを使い始めたばかりで、ベストプラクティスを念頭に置いて始めようとしています。
基本的に、私は誰かが彼らの経験を共有できるかどうか、他の開発者がどのような好みを持っているか、そして将来の落とし穴を避けるための最良の方法は何であるかを望んでいました。
import module
使用するのが最適かどうかについての包括的なガイドを見つけようとしましたfrom module import
。Pythonを使い始めたばかりで、ベストプラクティスを念頭に置いて始めようとしています。
基本的に、私は誰かが彼らの経験を共有できるかどうか、他の開発者がどのような好みを持っているか、そして将来の落とし穴を避けるための最良の方法は何であるかを望んでいました。
import module
との違いfrom module import foo
は主に主観的なものです。一番気に入ったものを選び、一貫して使用してください。ここでは、決定するのに役立ついくつかのポイントを示します。
import module
import
ステートメントのメンテナンスが少なくなります。モジュールの別のアイテムの使用を開始するために追加のインポートを追加する必要はありませんmodule.foo
するのは面倒で冗長な場合があります (退屈は、import module as mo
次に入力することで最小限に抑えることができますmo.foo
) 。from module import foo
foo
import
ステートメントを更新する必要がありますfoo
。たとえばceil()
、math.ceil()
どちらの方法でもかまいませんが、使用しないでくださいfrom module import *
。
合理的な大規模なコード セットの場合、import *
それをモジュールに固定する可能性が高い場合は、削除できません。これは、コードで使用されているアイテムが「モジュール」から来ているかどうかを判断するのが難しいためです。これにより、もう使用していないと思われるポイントに簡単に到達できますimport
が、それを確認することは非常に困難です。
モジュールへの書き込みに関連する、言及されていない別の詳細がここにあります。確かに、これはあまり一般的ではないかもしれませんが、時々必要になりました。
Python での参照と名前バインディングの仕組みにより、モジュール内のシンボル、たとえば foo.bar をそのモジュールの外から更新し、他のインポート コードでその変更を「参照」する場合は、foo をインポートする必要があります。特定の方法。例えば:
モジュール foo:
bar = "apples"
モジュール a:
import foo
foo.bar = "oranges" # update bar inside foo module object
モジュール b:
import foo
print foo.bar # if executed after a's "foo.bar" assignment, will print "oranges"
ただし、モジュール名の代わりにシンボル名をインポートすると、これは機能しません。
たとえば、モジュール a でこれを行うと:
from foo import bar
bar = "oranges"
私の設定はa
module内の名前「バー」に影響を与えただけで、モジュールオブジェクトに「到達」してその.bar
bar
a
foo
bar
多くの人がimport
vsについてすでに説明しimport from
ていますが、内部で何が起こっているのか、そしてそれが変化するすべての場所がどこにあるのかについて、もう少し説明したいと思います。
import foo
:をインポートfoo
し、現在の名前空間でそのモジュールへの参照を作成します。次に、モジュール内から特定の属性またはメソッドにアクセスするための完全なモジュール パスを定義する必要があります。
たとえばfoo.bar
、そうではありませんbar
from foo import bar
:をインポートfoo
し、リストされたすべてのメンバーへの参照を作成します ( bar
)。変数を設定しませんfoo
。
例: bar
but not baz
orfoo.baz
from foo import *
:をインポートfoo
し、現在の名前空間でそのモジュールによって定義されたすべてのパブリック オブジェクトへの参照を作成します (存在する__all__
場合は にリストされて__all__
いるすべて、存在しない場合は で始まらないすべて_
)。変数を設定しませんfoo
。
たとえばbar
and であり、 orではありbaz
ません。_qux
foo._qux
それでは、いつ行うか見てみましょうimport X.Y
:
>>> import sys
>>> import os.path
sys.modules
名前os
と で確認してくださいos.path
:
>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
およびを使用して名前空間のディクテーションを確認globals()
します。locals()
os
os.path
>>> globals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> locals()['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> globals()['os.path']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'os.path'
>>>
os
上記の例から、ローカルおよびグローバル名前空間にのみ挿入されることがわかりました。したがって、次を使用できるはずです。
>>> os
<module 'os' from
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> os.path
<module 'posixpath' from
'/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>
しかし、そうではありませんpath
。
>>> path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>
from locals() 名前空間を削除すると、sys.modules に存在する場合と同様os
にアクセスできなくなります。os
os.path
>>> del locals()['os']
>>> os
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>> os.path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>
import from
。from
:>>> import sys
>>> from os import path
sys.modules
します。os
os.path
>>> sys.modules['os']
<module 'os' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/os.pyc'>
>>> sys.modules['os.path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
をsys.modules
使用して、以前と同じように見つけたことがわかりましたimport name
locals()
では、globals()
名前空間のディクテーションでどのように見えるかを確認しましょう。
>>> globals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> locals()['path']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['os']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'os'
>>>
path
ではなく名前を使用してアクセスできますos.path
。
>>> path
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> os.path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'os' is not defined
>>>
から「パス」を削除しましょうlocals()
:
>>> del locals()['path']
>>> path
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'path' is not defined
>>>
エイリアスを使用した最後の例:
>>> from os import path as HELL_BOY
>>> locals()['HELL_BOY']
<module 'posixpath' from '/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>> globals()['HELL_BOY']
<module 'posixpath' from /System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/posixpath.pyc'>
>>>
そして、パスが定義されていません:
>>> globals()['path']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'path'
>>>
両方の方法がサポートされているのには理由があります。一方が他方よりも適切な場合があります。
import module
: モジュールの多くのビットを使用している場合に便利です。欠点は、各参照をモジュール名で修飾する必要があることです。
from module import ...
: インポートされたアイテムがモジュール名のプレフィックスなしで直接使用できるのは素晴らしいことです。欠点は、使用するすべてのものをリストする必要があることと、何かがどこから来たのかがコードで明確でないことです。
どちらを使用するかは、どちらがコードを明確にして読みやすくするかに依存し、個人の好みと少なからず関係があります。import module
コードでは、オブジェクトまたは関数がどこから来たのかが非常に明確であるため、私は一般的に傾いています。from module import ...
コードでオブジェクト/関数を頻繁に使用しているときに使用します。
個人的にいつも使っている
from package.subpackage.subsubpackage import module
そして、次のようにすべてにアクセスします
module.function
module.modulevar
その理由は、呼び出しが短いと同時に、各ルーチンのモジュール名前空間を明確に定義しているためです。これは、ソース内の特定のモジュールの使用法を検索する必要がある場合に非常に役立ちます。
言うまでもなく、名前空間を汚染し、特定の関数がどこから来たのか (どのモジュールから) がわからないため、 import * を使用しないでください。
もちろん、次のように、2 つの異なるパッケージ内の 2 つの異なるモジュールに同じモジュール名を使用すると、問題が発生する可能性があります。
from package1.subpackage import module
from package2.subpackage import module
この場合、もちろん問題に遭遇しますが、パッケージのレイアウトに欠陥があるという強いヒントがあり、再考する必要があります。
import module
モジュールから多くの機能を使用する場合に最適です。
from module import function
のみが必要な場合に、モジュールのすべての関数と型でグローバル名前空間を汚染するのを避けたい場合に最適ですfunction
。
これら 2 つの方法の間にもう 1 つの微妙な違いがあることを発見しました。
モジュールfoo
が次のインポートを使用する場合:
from itertools import count
その場合、モジュールbar
は誤ってではなく でcount
定義されているかのように使用される可能性があります。foo
itertools
import foo
foo.count()
使用する場合foo
:
import itertools
間違いはまだ可能性がありますが、発生する可能性は低くなります。bar
する必要がある:
import foo
foo.itertools.count()
これは私にいくつかの問題を引き起こしました。モジュールを定義していないモジュールから誤って例外をインポートし、他のモジュールからのみインポートしたモジュールがありました(を使用from module import SomeException
)。インポートが不要になり削除されたとき、問題のモジュールは壊れていました。
言及されていない別の違いがあります。これはhttp://docs.python.org/2/tutorial/modules.htmlから逐語的にコピーされたものです
使用時のご注意
from package import item
項目は、パッケージのサブモジュール (またはサブパッケージ)、または関数、クラス、変数など、パッケージで定義された他の名前のいずれかです。import ステートメントは、最初に項目がパッケージで定義されているかどうかをテストします。そうでない場合は、それがモジュールであると想定し、ロードを試みます。見つからない場合は、ImportError 例外が発生します。
逆に、次のような構文を使用する場合
import item.subitem.subsubitem
最後のアイテムを除く各アイテムはパッケージである必要があります。最後の項目はモジュールまたはパッケージにすることができますが、前の項目で定義されたクラス、関数、または変数にすることはできません。
import package
import module
ではimport
、トークンはモジュール (Python コマンドを含むファイル) またはパッケージ (sys.path
ファイルを含む 内のフォルダー) である必要があります__init__.py
。
サブパッケージがある場合:
import package1.package2.package
import package1.package2.module
フォルダー (パッケージ) またはファイル (モジュール) の要件は同じですが、フォルダーまたはファイルは 内package2
にある必要がありpackage1
、 と の両方package1
にファイルpackage2
が含まれている必要があり__init__.py
ます。https://docs.python.org/2/tutorial/modules.html
from
インポートのスタイル:
from package1.package2 import package
from package1.package2 import module
パッケージまたはモジュールは、import
ステートメントを含むファイルの名前空間に、 ではなくmodule
(またはpackage
)として入りますpackage1.package2.module
。より便利な名前にいつでもバインドできます。
a = big_package_name.subpackage.even_longer_subpackage_name.function
from
特定の関数または変数に名前を付けることができるのは、インポートのスタイルのみです。
from package3.module import some_function
許可されていますが、
import package3.module.some_function
許可されていません。
人々が言ったことに付け加えるとfrom x import *
、名前の由来がわかりにくくなるだけでなく、Pylint などのコード チェッカーが無効になります。これらの名前は未定義の変数として報告されます。
これに対する私自身の答えは、まず、使用するモジュールの数に大きく依存します。1 つまたは 2 つしか使用しない場合は、from
...を使用することがよくあります。import
ファイルの残りの部分でキーストロークが少なくなるためです。しかし、多くの異なるモジュールを使用する場合は、import
これは、各モジュール参照が自己文書化されていることを意味するためです。探し回らなくても、各シンボルがどこから来ているかを確認できます。
通常、私は単純なインポートの自己文書化スタイルを好み、インポートするモジュールが 1 つしかない場合でも、モジュール名を入力する必要がある回数が 10 から 20 を超えたときにのみ from.. import に変更します。
Jan Wrobelが言及しているように、さまざまなインポートの 1 つの側面は、インポートがどのように開示されるかです。
モジュールmymath
from math import gcd
...
mymathの使用:
import mymath
mymath.gcd(30, 42) # will work though maybe not expected
gcd
のユーザーに開示しないように、内部使用のみを目的としてインポートした場合mymath
、これは不便な場合があります。私はこれをかなり頻繁に持っており、ほとんどの場合、「モジュールをきれいに保ちたい」と思っています。
代わりに使用することでこれをもう少しあいまいにするというJan Wrobelの提案とは別にimport math
、私は先頭のアンダースコアを使用してインポートを開示から隠し始めました。
# for instance...
from math import gcd as _gcd
# or...
import math as _math
大規模なプロジェクトでは、この「ベスト プラクティス」により、後続のインポートで何を公開し、何を公開しないかを正確に制御できます。これにより、モジュールがきれいに保たれ、プロジェクトの特定のサイズで元が取れます。
モジュールのインポート - モジュールから別のものを取得するための追加の作業は必要ありません。冗長な入力などの欠点があります
モジュールのインポート元 - 入力を減らし、モジュールのどのアイテムにアクセスできるかをより詳細に制御します。モジュールから新しいアイテムを使用するには、インポート ステートメントを更新する必要があります。