回答:
バイトコードレベルの唯一の違いは、.extend
方法には関数呼び出しが含まれることです。これは、Pythonではよりも少し高価INPLACE_ADD
です。
この操作を何十億回も実行しているのでない限り、心配する必要はありません。ただし、ボトルネックは他の場所にある可能性があります。
.__iadd__()
/ .__add__()
/ .__radd__()
対.extend()
非ローカル変数(関数に対してローカルではなく、グローバルでもない変数)に+ =を使用することはできません
def main():
l = [1, 2, 3]
def foo():
l.extend([4])
def boo():
l += [5]
foo()
print l
boo() # this will fail
main()
これは、拡張ケースのコンパイラが命令l
を使用して変数をロードするためですLOAD_DEREF
が、+ =の場合はLOAD_FAST
- が使用され、*UnboundLocalError: local variable 'l' referenced before assignment*
関数呼び出しを連鎖させることはできますが、関数呼び出しを直接+ =することはできません。
class A:
def __init__(self):
self.listFoo = [1, 2]
self.listBar = [3, 4]
def get_list(self, which):
if which == "Foo":
return self.listFoo
return self.listBar
a = A()
other_list = [5, 6]
a.get_list("Foo").extend(other_list)
a.get_list("Foo") += other_list #SyntaxError: can't assign to function call
CPython 3.5.2のソースコードはありません大きな違い:。
static PyObject *
list_inplace_concat(PyListObject *self, PyObject *other)
{
PyObject *result;
result = listextend(self, other);
if (result == NULL)
return result;
Py_DECREF(result);
Py_INCREF(self);
return (PyObject *)self;
}
extend()は任意の反復可能*で機能し、+ =は一部で機能しますが、ファンキーになる可能性があります。
import numpy as np
l = [2, 3, 4]
t = (5, 6, 7)
l += t
l
[2, 3, 4, 5, 6, 7]
l = [2, 3, 4]
t = np.array((5, 6, 7))
l += t
l
array([ 7, 9, 11])
l = [2, 3, 4]
t = np.array((5, 6, 7))
l.extend(t)
l
[2, 3, 4, 5, 6, 7]
Python 3.6
*かなり確かに.extend()はイテラブルで動作しますが、私が正しくない場合はコメントしてください
list.extend(iterable) Extend the list by appending all the items from the iterable. Equivalent to a[len(a):] = iterable.
私は自分のアスタリスクに答えたと思います。
+=
(質問のように2つのリストとは対照的に)異なるタイプのオブジェクトで演算子を使用する場合、オブジェクトの連結が得られるとは期待できません。そして、list
返される型があることを期待することはできません。あなたのコードを見てください、あなたはnumpy.ndarray
代わりにを取得しますlist
。
実際には、そこに3つのオプションの違いは以下の通りですADD
、INPLACE_ADD
とextend
。前者は常に低速ですが、他の2つはほぼ同じです。
この情報については、を使用したいと思いますextend
。これは、よりも速く、ADD
あなたが何をしているのかをより明確に示していますINPLACE_ADD
。
次のコードを数回試してください(Python 3の場合):
import time
def test():
x = list(range(10000000))
y = list(range(10000000))
z = list(range(10000000))
# INPLACE_ADD
t0 = time.process_time()
z += x
t_inplace_add = time.process_time() - t0
# ADD
t0 = time.process_time()
w = x + y
t_add = time.process_time() - t0
# Extend
t0 = time.process_time()
x.extend(y)
t_extend = time.process_time() - t0
print('ADD {} s'.format(t_add))
print('INPLACE_ADD {} s'.format(t_inplace_add))
print('extend {} s'.format(t_extend))
print()
for i in range(10):
test()
ADD 0.3540440000000018 s
INPLACE_ADD 0.10896000000000328 s
extend 0.08370399999999734 s
ADD 0.2024550000000005 s
INPLACE_ADD 0.0972940000000051 s
extend 0.09610200000000191 s
ADD 0.1680199999999985 s
INPLACE_ADD 0.08162199999999586 s
extend 0.0815160000000077 s
ADD 0.16708400000000267 s
INPLACE_ADD 0.0797719999999913 s
extend 0.0801490000000058 s
ADD 0.1681250000000034 s
INPLACE_ADD 0.08324399999999343 s
extend 0.08062700000000689 s
ADD 0.1707760000000036 s
INPLACE_ADD 0.08071900000000198 s
extend 0.09226200000000517 s
ADD 0.1668420000000026 s
INPLACE_ADD 0.08047300000001201 s
extend 0.0848089999999928 s
ADD 0.16659500000000094 s
INPLACE_ADD 0.08019399999999166 s
extend 0.07981599999999389 s
ADD 0.1710910000000041 s
INPLACE_ADD 0.0783479999999912 s
extend 0.07987599999999873 s
ADD 0.16435900000000458 s
INPLACE_ADD 0.08131200000001115 s
extend 0.0818660000000051 s
ADD
でINPLACE_ADD
してextend()
。ADD
新しいリストを作成し、2つの元のリストの要素をそのリストにコピーします。確かに、INPLACE_ADD
およびのインプレース操作よりも遅くなりextend()
ます。
私は公式のPythonチュートリアルを調べましたが、このトピックについて何も見つかりませんでした
この情報は、たまたまプログラミングFAQに埋め込まれています。
...リストの場合、
__iadd__
[ie+=
]はextend
リストを呼び出してリストを返すことと同じです。だからこそ、リストの場合+=
は、list.extend
これは、CPythonソースコードでも確認できます。https://github.com/python/cpython/blob/v3.8.2/Objects/listobject.c#L1000-L1011
Python for Data Analysisによると。
「追加によるリストの連結は、新しいリストを作成してオブジェクトをコピーする必要があるため、比較的コストのかかる操作です。特に大きなリストを作成している場合は、extendを使用して既存のリストに要素を追加することをお勧めします。」したがって、
everything = []
for chunk in list_of_lists:
everything.extend(chunk)
連結代替よりも高速です:
everything = []
for chunk in list_of_lists:
everything = everything + chunk
everything = everything + temp
は必ずしもと同じ方法で実装されるとは限りませんeverything += temp
。
everything += temp
は、everything
コピーする必要がないように実装されています。これはほとんどあなたの答えを根拠のないものにします。
.__iadd__()
/.__add__()
/.__radd__()
対をサポートする場合、より多くの意味を持っています.extend()