두 목록을 연결- '+ ='와 extend ()의 차이점


243

실제로 파이썬에서 목록을 연결하는 두 가지 방법이있을 수 있습니다. 한 가지 방법은 extend () 메소드를 사용하는 것입니다.

a = [1, 2]
b = [2, 3]
b.extend(a)

다른 하나는 더하기 (+) 연산자를 사용합니다.

b += a

이제 두 가지 옵션 중 어느 것이 연결을 나열하는 '파이 토닉'방법이며 둘 사이에 차이점이 있습니까?


1
이 덕 타이핑에 올 때 아마의 차이는 더 의미가있는 경우, 어쩌면-하지-정말-A-목록 -하지만 같은-A-목록 지원 .__iadd__()/ .__add__()/ .__radd__().extend()
닉 T

답변:


214

바이트 코드 수준의 유일한 차이점 .extend은 함수 호출과 관련 이 있다는 것입니다.이 함수 호출은 Python보다 약간 비쌉니다 INPLACE_ADD.

이 작업을 수십억 번 수행하지 않으면 걱정할 것이 없습니다. 그러나 병목 현상이 다른 곳에있을 수 있습니다.


16
어쩌면 차이가 덕 타이핑과 관련하여 더 많은 의미를 가질 수 있으며 아마도 목록이 아닌 목록을 지원하는 경우 .__iadd__()/ .__add__()/ .__radd__()vs.extend()
Nick T

8
이 답변은 중요한 범위 차이를 언급하지 않습니다.
wim

3
실제로는 extends가 INPLACE_ADD ()보다 빠릅니다 (예 : 목록 연결). gist.github.com/mekarpeles/3408081
Archit Kapoor

178

로컬 변수가 아닌 변수에 + =를 사용할 수 없습니다 (변수는 함수에 대해 로컬 변수가 아니며 전역 변수가 아닙니다)

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*


4
나는 " 함수를 위해 지역적 이지 않고 전역아닌 변수"라는 설명에 어려움을 겪고 있습니다. 그러한 변수의 예를들 수 있습니까?
Stephane Rolland

8
내 예제에서 변수 'l'은 정확히 그런 종류입니다. 'foo'및 'boo'함수 (범위 밖)에는 로컬이 아니지만 전역이 아닙니다 (모듈 수준이 아닌 'main'func 내에 정의 됨)
monitorius

3
이 오류가 여전히 python 3.4.2에서 발생한다는 것을 확인할 수 있습니다 (인쇄하기 위해 괄호를 추가해야하지만 다른 모든 내용은 동일하게 유지할 수 있음).
trichoplax

7
맞습니다. 그러나 적어도 파이썬 3 에서는 boononlocal l 문을 사용할 수 있습니다 .
monitorius

컴파일러-> 인터프리터?
joelb

42

함수 호출을 연결할 수는 있지만 함수 호출을 직접 + = 할 수는 없습니다.

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

8

나는 numpy와 관련하여 약간의 차이가 있다고 말할 것입니다 (방금 질문은 numpy 배열이 아닌 두 목록을 연결하는 것에 대해 질문하는 것을 보았지만 초보자와 같은 문제 일 수 있기 때문에 이것이 누군가를 도울 수 있기를 바랍니다. 예를 들어이 게시물에 대한 해결책을 찾는 사람).

import numpy as np
a = np.zeros((4,4,4))
b = []
b += a

오류와 함께 반환됩니다

ValueError : 피연산자를 셰이프 (0,)와 함께 브로드 캐스트 할 수 없습니다 (4,4,4)

b.extend(a) 완벽하게 작동


5

로부터 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;
}

4

extend ()는 iterable *과 함께 작동하고 + =는 일부와 작동하지만 펑키 할 수 있습니다.

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 ()가 iterable과 작동하지만 내가 틀렸다면 의견을 말하십시오.


튜플은 확실히 반복 가능하지만 extend () 메소드가 없습니다. extend () 메소드는 반복과 관련이 없습니다.
wombatonfire

.extend는리스트 클래스의 메소드입니다. 파이썬 문서에서 : list.extend(iterable) Extend the list by appending all the items from the iterable. Equivalent to a[len(a):] = iterable.나는 내 별표에 대답했다고 생각한다.
grofte

아, 당신은 extend ()를 반복 할 수 있다는 것을 의미했습니다. "extend () is iterable for iterable" "이라고 읽었습니다. :) 내 나쁜 점은 있지만 조금 모호하게 들립니다.
wombatonfire

1
결국, 이것은 적어도이 질문의 맥락에서 좋은 예는 아닙니다. +=다른 유형의 객체 (질문과 같이 두 목록과 달리)와 함께 연산자 를 사용하면 객체가 연결될 것으로 기대할 수 없습니다. 그리고 당신은 list타입이 리턴 될 것이라고 기대할 수 없습니다 . 코드를 살펴보면 numpy.ndarray대신 대신을 얻을 수 list있습니다.
wombatonfire

2

실제로 세 가지 옵션 ( ADD, INPLACE_ADD및) 간에 차이가 있습니다 extend. 전자는 항상 느리지 만 다른 두 개는 거의 같습니다.

이 정보를 사용하여보다을 사용 하고 싶습니다.보다 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

2
ADD와 ( INPLACE_ADD과) 비교할 수 없습니다 extend(). ADD새 목록을 생성하고 두 개의 원본 목록 요소를 여기에 복사합니다. INPLACE_ADD그리고의 내부 작업보다 속도가 느려집니다 extend().
wombatonfire

나도 알아 이 예제의 요점은 목록을 갖는 다양한 방법을 모든 요소와 함께 비교하는 것입니다. 다른 작업을 수행하기 때문에 시간이 더 오래 걸리지 만 원래 객체를 그대로 유지하는 데 관심이있는 경우 알아 두는 것이 좋습니다.
dalonsoa

1

공식 Python 튜토리얼을 찾았지만이 주제에 대해 아무것도 찾을 수 없었습니다.

이 정보는 프로그래밍 FAQ에 묻혀 있습니다 .

... 목록의 경우 __iadd__[ie +=]는 extend목록 을 호출 하고 목록을 반환하는 것과 같습니다 . 우리는 목록에 대해 말할 이유 +=는 "속기는"입니다list.extend

CPython 소스 코드에서 직접 확인할 수도 있습니다. https://github.com/python/cpython/blob/v3.8.2/Objects/listobject.c#L1000-L1011


-1

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

여기에 이미지 설명을 입력하십시오 여기에 이미지 설명을 입력하십시오


4
everything = everything + temp반드시와 같은 방식으로 구현되지는 않습니다 everything += temp.
David Harrison

1
네 말이 맞아 알림 주셔서 감사합니다. 그러나 내 요점은 효율성의 차이에 관한 것입니다.
:)

6
@ littlebear333 everything += tempeverything복사 할 필요가없는 방식으로 구현됩니다 . 이것은 당신의 대답을 논점으로 만듭니다.
nog642
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.