「モジュールのインポート」と「モジュールのインポート機能から」


143

私は常にこの方法を使用しています:

from sys import argv

argvargvだけで使用します。ただし、これを使用する規則があります。

import sys

とによってargvを使用して sys.argv

2番目の方法は、コードを自己文書化し、私は(本当に)それに従います。しかし、私が最初の方法を好む理由は、モジュール全体をインポートするのではなく、必要な関数のみをインポートするためです(Pythonはそれらをインポートするのに時間を浪費する無駄な関数を含んでいます)。argvだけが必要であり、sysの他のすべての関数は役に立たないことに注意してください。

だから私の質問は。最初の方法は本当にスクリプトを高速化しますか?どの方法が最も好まれますか?どうして?



回答:


175

モジュールをインポートしても何も無駄になりません。モジュールは常に完全にsys.modulesマッピングに)インポートされるため、使用するimport sysかどうかfrom sys import argvは関係ありません。

2つのステートメントの唯一の違いは、バインドされる名前です。モジュールにimport sys名前sysをバインドし(so- sys> sys.modules['sys'])、from sys import argv別の名前をバインドargvします。モジュール内に含まれる属性を直接指します(so- argv> sys.modules['sys'].argv)。sysモジュールの他のものを使用するかどうかに関係なく、モジュールの残りの部分はまだそこにあります。

また、2つのアプローチの間にパフォーマンスの違いはありません。はい、sys.argv2つのことを調べる必要があります。それは、ルックアップするために持っているsysあなたのグローバル名前空間に(モジュールを見つけた)、その後、属性を調べますargv。そして、はい、from sys import argvすでに属性への直接参照を持っているので、使用することで属性検索をスキップできます。しかし、importステートメントはまだその作業を行う必要があり、インポート時に同じ属性を検索し、argv 一度だけ使用する必要があります。argvループで何千回も使用する必要がある場合、おそらく違いが生じる可能性がありますが、この特定のケースでは実際には違いはありません。

その場合、どちらか一方の選択は、代わりにコーディングスタイルに基づいている必要があります。

大規模なモジュール、私は確かに使うだろうimport sys。コードのドキュメントが重要でありsys.argv、大きなモジュールのどこかを使用すると、参照しているものがargv今までよりもずっと明確になります。

使用する唯一の場所が関数を呼び出すブロックargv内にある場合、それについて満足している場合は必ず使用してください:'__main__'main()from sys import argv

if __name__ == '__main__':
    from sys import argv
    main(argv)

私はまだimport sys自分でそこを使用します。すべてのものが等しい(正確には、パフォーマンス書き込みに使用される文字数の点で)ので、それは私にとっては簡単です。

他のものをすべてインポートする場合、おそらくパフォーマンスが影響します。ただし、たとえば重要なループなどで、モジュール内で特定の名前を何度も使用する場合のみです。ただし、(関数内での)ローカル名の作成はさらに高速になります。

 import somemodule

 def somefunction():
      localname = somemodule.somefunctionorother
      while test:
          # huge, critical loop
          foo = localname(bar)

1
また、最上位パッケージ内のサブパッケージ/モジュールのいずれかの属性を公開するサブパッケージまたはモジュールを含むパッケージがある場合もあります。使い方はfrom...importあなたがすることができますpackage.attributeではなく、package.subpackage_or_module.attributeあなたがパッケージ内に論理的または概念的なグループを持っていますが、パッケージのユーザーのために物事が少しより便利にしたい場合に便利です。(numpyこのようなことを行うと思います。)
JAB 14年

djangoにfrom django.core.management.base import BaseCommandは、より良いものがたくさんあるスポットがあり、それ以外のもの(特にimport django)はコードが読めない可能性があります。したがって、私はこの答えが好きですが、いくつかのライブラリー(特にいくつかのフレームワーク)には、慣例がベアインポートに違反するものがあると思います。いつものように、与えられた状況で何が最善かについてあなたの判断を使用してください。しかし、明示的な側の誤り(言い換えれば、私はほとんどの部分に同意します)。
ニューロネット

1
@JAB:import ... as別の名前のパッケージを見つけるために引き続き使用できます:import package.subpackage_or_module as shortnamefrom parent import sub本質的に同じことをします。
マーティンピーターズ

43

import moduleよりも使用することを支持する2つの理由がありますfrom module import function

最初は名前空間です。関数をグローバル名前空間にインポートすると、名前の衝突のリスクがあります。

2つ目は、標準モジュールには関係ありませんが、特に開発中のモジュールを所有している場合は重要です。reload()モジュールのオプションです。このことを考慮:

from module import func
...
reload(module)
# func still points to the old code

一方

import module
...
reload(module)
# module.func points to the new code

速度については...

モジュール全体をインポートするのではなく、必要な関数のみをインポートします(Pythonがインポートに時間を浪費する無駄な関数が含まれています)

モジュールをインポートする場合でも、モジュールから関数をインポートする場合でも、Pythonはモジュール全体を解析します。いずれにしても、モジュールはインポートされます。「関数のインポート」とは、関数を名前にバインドすることです。実際にimport moduleは通訳者にとっては仕事が少ないですfrom module import func


6
reload()はPython 2に組み込まれていました。それはもはやPythonの3のケースである
アンドレ・

循環インポートの依存関係にも影響があると思いましたか?
ADP

18

from import読みやすさを改善する場合は常にs を使用します。たとえば、私は好む(セミコロンはここのスペースを節約することだけである):

from collections import defaultdict
from foomodule import FooBar, FooBaz
from twisted.internet.protocol import Factory
defaultdict(); FooBar(); FooBaz(); Factory()

の代わりに:

import collections
import foomodule
import twisted.internet.protocol
collections.defaultdict(); foomodule.FooBar(); foomodule.FooBaz()
twisted.internet.protocol.Factory()

後者は非常に多くの冗長な情報を含んでいるので、私にとっては読みにくいです。また、モジュールのどの部分を使用しているかを事前に知ることは有用です。

importモジュールから多くの短い名前を使用している場合、通常のs を好みます:

import sys
sys.argv; sys.stderr; sys.exit()

または、名前が非常に一般的であるため、名前空間の外では意味をなさない場合:

import json
json.loads(foo)

from json import loads
loads(foo)  # potentially confusing

これは私のお気に入りの答えです。「明示的は暗黙的よりも優れています」は、読みやすさ、単純さ、およびDRYと競合する場合があります。特にDjangoのようなフレームワークを使用する場合。
ニューロネット

18

私の意見では、定期的に使用importすると読みやすさが向上します。Pythonコードを確認するとき、指定された関数またはクラスがどこから来たのか、それが使用されている場所を見ることが好きです。その情報を取得するために、モジュールの上部にスクロールする必要がありません。

長いモジュール名については、asキーワードを使用し、短いエイリアスを指定します。

import collections as col
import foomodule as foo
import twisted.internet.protocol as twip

my_dict = col.defaultdict()
foo.FooBar()
twip_fac = twip.Factory()

例外として、モジュールfrom module import somethingを扱うときは常に表記法を使用し__future__ます。Python 2でデフォルトですべての文字列をUnicodeにしたいときは、別の方法ではできません。

from __future__ import unicode_literals
from __future__ import print_function

アーメン!「としてインポート」は勝利の組み合わせです:
paj28

4

けれどもimport sysfrom sys import agrvの両方が、全体インポートsysモジュールを、後者はバインディング名を使用するので、唯一のargvモジュールは、コードの残りの部分にアクセス可能です。

一部の人々にとって、これはあなたが明示的に述べた機能にのみアクセスできるようにするので好ましいスタイルでしょう。

ただし、潜在的な名前の競合が発生します。別の名前のモジュールがある場合はどうなりますargvか?関数を明示的にインポートし、で名前を変更することもできます。from sys import argv as sys_argvこれは、明示的なインポートを満たし、名前空間の衝突を引き起こす可能性が低い規則です。


2
だから、どのif sys_argv:ように優れていif sys.argv:ますか?2番目のステートメントが何を意味するかは知っていますが、最初のフォームが何を意味するかは、奇妙なインポートまでさかのぼらないとわかりません。
msw

1

私は最近自分にこの質問をしました。私はさまざまな方法を計りました。

リクエストライブラリ

def r():
    import requests
    return 'hello'
timeit r() # output: 1000000 loops, best of 3: 1.55 µs per loop

def rg():
    from requests import get
    return 'hello'
timeit rg() # output: 100000 loops, best of 3: 2.53 µs per loop

beautifulsoupライブラリ

def bs():
    import bs4
    return 'hello' 
timeit bs() # output: 1000000 loops, best of 3: 1.53 µs per loop

def be():
    from bs4 import BeautifulSoup
    return 'hello'
timeit be() # output: 100000 loops, best of 3: 2.59 µs per loop

JSONライブラリ

def js():
    import json
    return 'hello'
timeit js() # output: 1000000 loops, best of 3: 1.53 µs per loop

def jl():
    from json import loads
    return 'hello'
timeit jl() # output: 100000 loops, best of 3: 2.56 µs per loop

sysライブラリ

def s():
    import sys
    return 'hello'
timeit s() # output: 1000000 loops, best of 3: 1.55 µs per loop

def ar():
    from sys import argv
    return 'hello'
timeit ar() # output: 100000 loops, best of 3: 2.87 µs per loop

パフォーマンスにはわずかな違いがあるように思えます。


属性ルックアップに追加しています。正しく比較import moduleするにfrom module import nameは、ケースにその名前検索を追加import moduleます。たとえばsys.argvarテストに行を追加するなど。異なるバイトコードが生成され、異なるコードパスが実行されるため、実行される作業がわずかに異なるため、まだ違いがあります。
マーティンピーターズ

2
答えの違いに直接対処することに注意してください。使用して違いがあるだろうimport sys、その後使用してsys.argvループ内での時間の数千人を対from sys import argvそしてちょうど使用argv。しかし、あなたはしません。モジュールのグローバルレベルで一度だけ行うことについては、タイミングの微妙な違いではなく、読みやすさのために本当に最適化する必要があります。
マーティンピーターズ

1
ああ!そして、私は何かに取り組んでいると思った!:)私はあなたの答えをざっと読みました。私はその上に銃をジャンプしたように見えます。謙虚になるのは気持ちがいい。
tmthyjames

-1

公開されたコードの断片を見て、モジュール全体をインポートして参照することmodule.functionは、少なくとも標準モジュールについてはほとんど標準です。1つの例外はdatetime

from datetime import datetime, timedelta

だからあなたはdatetime.now()むしろ言うことができますdatetime.datetime.now()

パフォーマンスが心配な場合は、いつでも言うことができます(たとえば)

argv = sys.argv

モジュールのルックアップは既に行われているため、パフォーマンスに重要なコードを実行します。ただし、これは関数/メソッドで機能しますが、ほとんどのIDEは混乱し、変数に割り当てられたときに関数のソースリンク/署名を表示しません。


-2

あなたが何かをするなら私はそれを追加したいだけです

from math import sin

(またはその他の組み込みのライブラリーのようなsysまたはがposix)、その後、sinあなたはすなわち、あなたのモジュール(のドキュメントに含まれる>>> help(mymodule)か、$ pydoc3 mymoduleこれを回避するには、インポート使用。:

import math
from math import sin as _sin

PS:組み込みライブラリは、Cコードからコンパイルされ、Pythonに含まれているライブラリです。argparseosおよびio組み込みパッケージではありません

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.