なぜ[]
より速いのですlist()
か?
最大の理由は、Pythonがlist()
ユーザー定義関数と同じように処理することです。つまり、他の何かにエイリアスを付けてそれをインターセプトし、list
別の何かを行うことができます(独自のサブクラスリストまたはおそらく両端キューを使用するなど)。
すぐに組み込みリストの新しいインスタンスを作成します[]
。
私の説明は、あなたにこれに対する直感を与えることを目的としています。
説明
[]
一般にリテラル構文と呼ばれます。
文法では、これを「リスト表示」と呼びます。ドキュメントから:
リスト表示は、角かっこで囲まれた空の一連の式です。
list_display ::= "[" [starred_list | comprehension] "]"
リスト表示は、新しいリストオブジェクトを生成します。内容は、式のリストまたは内包のいずれかによって指定されます。式のコンマ区切りのリストが指定されると、その要素は左から右に評価され、その順序でリストオブジェクトに配置されます。内包表記を指定すると、内包表記の結果の要素からリストが構成されます。
つまり、これはタイプの組み込みオブジェクトlist
が作成されることを意味します。
これを回避する方法はありません。つまり、Pythonはできる限り迅速に実行できます。
一方、ビルトインリストコンストラクターを使用してビルトインをlist()
作成することは阻止できますlist
。
たとえば、リストを騒々しく作成したいとします。
class List(list):
def __init__(self, iterable=None):
if iterable is None:
super().__init__()
else:
super().__init__(iterable)
print('List initialized.')
次にlist
、モジュールレベルのグローバルスコープで名前をインターセプトし、を作成するときにlist
、実際にサブタイプリストを作成します。
>>> list = List
>>> a_list = list()
List initialized.
>>> type(a_list)
<class '__main__.List'>
同様に、グローバル名前空間から削除することもできます
del list
組み込みの名前空間に配置します。
import builtins
builtins.list = List
そしていま:
>>> list_0 = list()
List initialized.
>>> type(list_0)
<class '__main__.List'>
また、リスト表示は無条件にリストを作成することに注意してください。
>>> list_1 = []
>>> type(list_1)
<class 'list'>
おそらくこれは一時的にのみ行うので、変更を元に戻します。まずList
、組み込みオブジェクトから新しいオブジェクトを削除します。
>>> del builtins.list
>>> builtins.list
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: module 'builtins' has no attribute 'list'
>>> list()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'list' is not defined
ああ、いや、元のトラックを見失いました。
心配する必要はありません。それでも取得できます。list
これはリストリテラルのタイプです。
>>> builtins.list = type([])
>>> list()
[]
そう...
なぜ[]
より速いのですlist()
か?
これまで見てきたように、上書きできますlist
が、リテラル型の作成をインターセプトすることはできません。使用するときlist
は、ルックアップを実行して、何かがあるかどうかを確認する必要があります。
次に、検索した呼び出し可能オブジェクトを呼び出す必要があります。文法から:
呼び出しは、おそらく空の一連の引数を使用して、呼び出し可能なオブジェクト(関数など)を呼び出します。
call ::= primary "(" [argument_list [","] | comprehension] ")"
リストだけでなく、どの名前でも同じことができることがわかります。
>>> import dis
>>> dis.dis('list()')
1 0 LOAD_NAME 0 (list)
2 CALL_FUNCTION 0
4 RETURN_VALUE
>>> dis.dis('doesnotexist()')
1 0 LOAD_NAME 0 (doesnotexist)
2 CALL_FUNCTION 0
4 RETURN_VALUE
[]
Pythonバイトコードレベルでは関数呼び出しがないためです。
>>> dis.dis('[]')
1 0 BUILD_LIST 0
2 RETURN_VALUE
バイトコードレベルでのルックアップや呼び出しを行わずに、リストを直接作成するだけです。
結論
私たちは、その証明されているlist
スコープ規則を使用してユーザーコードを傍受することができ、そのlist()
呼び出し可能なためルックスと、それを呼び出します。
一方[]
、リスト表示またはリテラルであるため、名前の検索と関数呼び出しを回避できます。
()
と''
彼らは唯一の空じゃないとして、特別で、彼らは、そのように、それはそれらシングルトンを作るための簡単な勝利は不変ですね。彼らは新しいオブジェクトを構築することすらせず、空のtuple
/のシングルトンをロードするだけstr
です。技術的には実装の詳細ですが、パフォーマンス上の理由から 、なぜそれらが空のtuple
/str
をキャッシュしないのか想像するのに苦労します。あなたの直感だから[]
と{}
株式リテラルをバック渡し間違っていたが、それはには適用されない()
と''
。