dict.clear ()와 파이썬에서 {} 할당의 차이점


167

파이썬에서 전화를 걸고 사전에 clear()할당하는 것에는 차이가 {}있습니까? 그렇다면 무엇입니까? 예:

d = {"stuff":"things"}
d.clear()   #this way
d = {}      #vs this way


이것이 가비지 수집 부분에 차이가 있는지 궁금합니다. .clear ()가 메모리 시스템에 더 좋을 것 같습니다.
Xavier Nicollet

답변:


285

동일한 사전을 참조하는 다른 변수가 있으면 큰 차이가 있습니다.

>>> d = {"stuff": "things"}
>>> d2 = d
>>> d = {}
>>> d2
{'stuff': 'things'}
>>> d = {"stuff": "things"}
>>> d2 = d
>>> d.clear()
>>> d2
{}

할당 d = {}하면 새로운 빈 사전이 만들어져 d변수에 할당되기 때문 입니다. 이 잎 d2아직도 항목과 이전 사전 가리키는. 그러나 d.clear()동일한 사전 dd2둘 다가 가리키는 사전을 지 웁니다 .


7
감사. 이것은 말이됩니다. 나는 여전히 파이썬에서 참조를 생성한다는 사고 방식에 익숙해 져야한다.
Marcin

15
= 이름에 대한 참조를 복사합니다. 파이썬에는 변수가 없으며 객체와 이름 만 있습니다.
tzot

17
"변수 없음"문장은 실제로 사실이지만 여기서는 실제로 도움이되지 않습니다. : 긴 파이썬 언어 문서는 여전히 "변수"에 대해 이야기로, 나는 아직도 용어를 사용하는거야 docs.python.org/reference/datamodel.html
그렉 Hewgill

9
tzot의 의견은 이름, 변수 및 사본 유형에 대한 내 생각을 조정하는 데 도움이된다는 것을 알았습니다. 그것을 pedantic이라고 부르는 것은 당신의 의견 일지 모르지만, 나는 그것이 불공평 한 가혹한 판단이라고 생각합니다.
cfwschmidt

1
또한 clear ()는 다른 사람이 여전히 참조 할 수있는 dict에서 제거 된 객체를 파괴하지 않습니다.
Lorenzo Belli

31

d = {}새 인스턴스를 d만들지 만 다른 모든 참조는 여전히 이전 내용을 가리 킵니다. d.clear()내용을 재설정하지만 동일한 인스턴스에 대한 모든 참조는 여전히 정확합니다.


21

다른 답변에서 언급 된 차이점 외에도 속도 차이도 있습니다. d = {}가 두 배 빠릅니다.

python -m timeit -s "d = {}" "for i in xrange(500000): d.clear()"
10 loops, best of 3: 127 msec per loop

python -m timeit -s "d = {}" "for i in xrange(500000): d = {}"
10 loops, best of 3: 53.6 msec per loop

9
dict이 비어 있으므로 실제로 모든 경우에 유효한 속도 테스트는 아닙니다. 큰 dict (또는 적어도 일부 내용)을 만들면 성능 차이가 훨씬 작아 질 것입니다 ... 가비지 수집기가 d = {} (?)에 약간의 상처를 줄 수도 있다고 생각합니다.
Rafe

3
@Rafe : 요점은 다른 변수가 사전 d를 가리 키지 않는다는 것을 알고 있다면 d = {}나중에 전체를 정리하는 것이 가비지 콜렉터에 남아있을 수 있으므로 설정 이 더 빨라야한다는 것입니다.
ViFI

8

이전에 이미 언급 한 것들에 대한 설명으로 :

>>> a = {1:2}
>>> id(a)
3073677212L
>>> a.clear()
>>> id(a)
3073677212L
>>> a = {}
>>> id(a)
3073675716L

이것은 .clear객체 를 수정하지만`= {}`는 새로운 객체를 생성 한다는 것을 보여줍니다 .
wizzwizz4

7

@odano의 답변 외에도 여러 번 받아 낸 내용 d.clear()을 지우려면 사용 속도가 더 빠릅니다.

import timeit

p1 = ''' 
d = {}
for i in xrange(1000):
    d[i] = i * i
for j in xrange(100):
    d = {}
    for i in xrange(1000):
        d[i] = i * i
'''

p2 = ''' 
d = {}
for i in xrange(1000):
    d[i] = i * i
for j in xrange(100):
    d.clear()
    for i in xrange(1000):
        d[i] = i * i
'''

print timeit.timeit(p1, number=1000)
print timeit.timeit(p2, number=1000)

결과는 다음과 같습니다.

20.0367929935
19.6444659233

4
차이가 중요한지 확신하지 못합니다. 어쨌든 내 컴퓨터에서 결과는 반대입니다!
Aristide

7

원본 객체의 범위가 아닌 경우 변경 방법은 항상 유용합니다.

def fun(d):
    d.clear()
    d["b"] = 2

d={"a": 2}
fun(d)
d          # {'b': 2}

사전을 다시 할당하면 새 객체가 만들어지고 원래 객체는 수정되지 않습니다.


4

언급되지 않은 한 가지는 범위 지정 문제입니다. 좋은 예는 아니지만 여기에 문제가 발생한 경우가 있습니다.

def conf_decorator(dec):
    """Enables behavior like this:
        @threaded
        def f(): ...

        or

        @threaded(thread=KThread)
        def f(): ...

        (assuming threaded is wrapped with this function.)
        Sends any accumulated kwargs to threaded.
        """
    c_kwargs = {}
    @wraps(dec)
    def wrapped(f=None, **kwargs):
        if f:
            r = dec(f, **c_kwargs)
            c_kwargs = {}
            return r
        else:
            c_kwargs.update(kwargs) #<- UnboundLocalError: local variable 'c_kwargs' referenced before assignment
            return wrapped
    return wrapped

이 솔루션은 대체하는 것입니다 c_kwargs = {}함께c_kwargs.clear()

누군가가 더 실용적인 예를 생각하면 자유롭게이 게시물을 편집하십시오.


global c_kwargs아마 작동하지 않을까요? 아마 global많이 사용하는 것이 가장 좋은 것은 아니지만.
fantabolous

3
@fantabolous를 사용 global하면 함수가 다르게 동작하게됩니다. conf_decorator에 대한 모든 호출은 동일한 c_kwargs 변수를 공유합니다. 파이썬 3 nonlocal이이 문제를 해결하기 위해 키워드를 추가 했다고 생각합니다.
Ponkadoodle

1

또한 때때로 dict 인스턴스는 dict의 하위 클래스 일 수 있습니다 ( defaultdict예 :) . 이 경우 clear정확한 유형의 dict을 기억할 필요가 없으며 중복 코드 (지우기 행을 초기화 행과 연결)를 피할 필요가 없으므로 사용하는 것이 좋습니다.

x = defaultdict(list)
x[1].append(2)
...
x.clear() # instead of the longer x = defaultdict(list)
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.