dict 리터럴과 dict 생성자를 사용하는 것에는 차이가 있습니까?


204

PyCharm을 사용하여 dict 리터럴 을 변환하는 것이 좋습니다 .

d = {
    'one': '1',
    'two': '2',
}

DICT 생성자 :

d = dict(one='1', two='2')

이러한 다양한 접근 방식이 중요한 방식으로 다릅니 까?

(이 질문을 쓰는 동안 dict()숫자 키를 지정하는 것이 불가능한 것 같습니다. .. d = {1: 'one', 2: 'two'}가능하지만 분명히 dict(1='one' ...)불가능합니다. 다른 것은 없습니까?)


4
dict()키-값 쌍의 목록과 명명 된 매개 변수를 허용하므로 사용하는 구문이 아니라 모든 유형의 dict를 만드는 데 사용할 수 있습니다. 또한 pyCharm에 버그 ( youtrack.jetbrains.net/issue/PY-2512 ) 가 있다는 사실은 아마도 가치가 있습니다.
Wooble

1
관련 : stackoverflow.com/questions/5790860/… (요약 : PyCharm의 동작이 느리고 추악합니다)
Wooble

1
분명히 CPython 2.7 dict ()는 더 느립니다 (6 배 더 늦습니까?). 참조 : doughellmann.com/2012/11/… 어쨌든 dicts와 함수 호출간에 코드를 입력하고 이동하는 것이 더 쉽기 때문에 어쨌든 생성자 구문을 선호하기 시작했습니다.
David Wheaton

2
공백을 잊지 마십시오. 두 번째 방법으로 공백이 포함 된 키를 만들 수 없습니다. 그러나 첫 번째 방법은 모든 문자열을 취할 수 있지만 신경 쓰지 않습니다. 물론 유니 코드에도 동일하게 적용됩니다.
CamilB

2
Python 2에서 dict(abc = 123)생성자는 바이트 문자열 키 'abc'를 사용하여 unicode_literals사전을 생성합니다 u'abc'. 사전 키를 사용 하고 유니 코드 일 것으로 예상 하는 경우 놀랍습니다 . stackoverflow.com/questions/20357210/…을 참조하십시오 .
Li-aung Yip

답변:


116

나는 당신이 가장 분명한 차이점을 지적했다고 생각합니다. 그 외에도,

첫 번째는 dict조금 더 빨라야하는 조회 할 필요가 없습니다.

두 번째 외모까지 dict에서 locals()다음 globals()당신이라는 지역 정의에 의해 동작을 전환 할 수 있도록하고, 발견 내장은, dict난 아무데도 생각할 수 있지만 예 :이 때 디버깅 어쩌면 떨어져 좋은 아이디어 일 것입니다


4
로컬 dict라는 로컬이 유용한 예 : stackoverflow.com/a/7880276/313113
bitek

또한 dict ()을 사용하면 먼저 dict ()에 대한 인수에 대한 dict을 구성한 다음 실제 dict 인스턴스가 작성 될 두 번째 dict를 작성합니다. 교정기는 dict 인스턴스를 한 번에 작성합니다.
NeilG

56

리터럴은 일반 CALL_FUNCTION 대신 최적화 된 BUILD_MAP 및 STORE_MAP opcode를 사용하므로 훨씬 빠릅니다.

> python2.7 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.958 usec per loop

> python2.7 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.479 usec per loop

> python3.2 -m timeit "d = dict(a=1, b=2, c=3, d=4, e=5)"
1000000 loops, best of 3: 0.975 usec per loop

> python3.2 -m timeit "d = {'a':1, 'b':2, 'c':3, 'd':4, 'e':5}"
1000000 loops, best of 3: 0.409 usec per loop

10
@Ned : 대부분의 사용자에게는 대부분 중요하지 않지만 수백만 또는 수십억 개의 항목이 생성되고 2 배 속도 향상이 의미가있는 상황이 있습니다.
Mr Fooz

5
@ MrFooz : 그런 상황이 있습니다. 마이크로 타이밍을하는 사람들의 99.9 %가 그러한 상황에 있지 않다는 것을 알게 될 것입니다.
Ned Batchelder

29
@Ned 스레드가 어느 쪽이 더 빠르 냐고 묻습니다.
Elliott

11
@Elliot OP는 어느 쪽이 더 빠른지 묻지 않았습니다.
Tom Ferguson

5
소스의 dict 리터럴에서 수백만 개의 dicts 또는 수백만 개의 키로 하나의 dict을 생성하는 경우 잘못하고 있습니다.
jwg

41

그들은 파이썬 3.2에서 거의 동일하게 보입니다.

gnibbler가 지적했듯이 첫 번째는 조회 할 필요가 없으므로 dict조금 더 빨라야합니다.

>>> def literal():
...   d = {'one': 1, 'two': 2}
...
>>> def constructor():
...   d = dict(one='1', two='2')
...
>>> import dis
>>> dis.dis(literal)
  2           0 BUILD_MAP                2
              3 LOAD_CONST               1 (1)
              6 LOAD_CONST               2 ('one')
              9 STORE_MAP
             10 LOAD_CONST               3 (2)
             13 LOAD_CONST               4 ('two')
             16 STORE_MAP
             17 STORE_FAST               0 (d)
             20 LOAD_CONST               0 (None)
             23 RETURN_VALUE
>>> dis.dis(constructor)
  2           0 LOAD_GLOBAL              0 (dict)
              3 LOAD_CONST               1 ('one')
              6 LOAD_CONST               2 ('1')
              9 LOAD_CONST               3 ('two')
             12 LOAD_CONST               4 ('2')
             15 CALL_FUNCTION          512
             18 STORE_FAST               0 (d)
             21 LOAD_CONST               0 (None)
             24 RETURN_VALUE

일부 구현에서 이것은 실제로 "작은 비트"가 아니며, 100의 계수와 비슷합니다.$ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' "{'a': 1, 'b': 2, 'c': 3}" ....... Mean +- std dev: 1.73 ns +- 0.14 ns $ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' '{k:v for k,v in i}' ....... Mean +- std dev: 139 ns +- 10 ns $ pypy -m perf timeit -l '1000000' -n '5' -s 'i=(("a",1), ("b", 2), ("c", 3))' 'dict(i)' ....... Mean +- std dev: 188 ns +- 16 ns
DylanYoung

13

이 두 가지 접근법은 앞서 언급했듯이 파이썬의 어휘 규칙이 방해하는 경우를 제외하고는 동일한 사전을 생성합니다.

사전 리터럴은 좀 더 분명한 사전이며, 모든 종류의 키를 만들 수 있지만 키 이름을 인용해야합니다. 반면에 어떤 이유로 필요한 경우 키에 변수를 사용할 수 있습니다.

a = "hello"
d = {
    a: 'hi'
    }

dict()생성자 때문에 걸리는 입력 형태의 다양한 당신에게 더 많은 유연성을 제공합니다. 예를 들어, 반복자 쌍을 제공 할 수 있으며이를 키 / 값 쌍으로 취급합니다.

PyCharm이 한 양식을 다른 양식으로 변환하도록 제안하는 이유를 모르겠습니다.


2
글쎄, 나는 PyCharm이 더 멋지게하려고 노력하고 있다고 생각합니다. 작은 따옴표로 묶은 문자열을 큰 따옴표로 변환하는 것을 항상 제공하는 것처럼 명백한 이유가 없습니다.
maligree

1
키가 문자열 인 경우 키만 인용하면됩니다. 그것들은 얼어 붙은 수레의 튜플처럼 쉽게 추할 수 있지만 조금 추한 것 같습니다.
Wooble

7

python 3.4 + pycharm의 큰 차이점은 키 수가 256을 초과하면 dict () 생성자가 "구문 오류"메시지를 생성한다는 것입니다.

나는 dict 리터럴을 사용하는 것을 선호합니다.


3
파이썬 3.4가 아닙니다. CPython <3.7에는 최대 255 개의 리터럴 인수가 호출 가능 항목에 전달 되었기 때문입니다. ( stackoverflow.com/a/8932175/2718295 )
cowbert

6

파이썬 2.7 튜토리얼에서 :

한 쌍의 중괄호는 {} 빈 사전을 작성합니다. 괄호 안에 쉼표로 구분 된 키 : 값 쌍 목록을 배치하면 사전에 초기 키 : 값 쌍이 추가됩니다. 이것은 또한 사전이 출력에 쓰여지는 방식입니다.

tel = {'jack': 4098, 'sape': 4139}
data = {k:v for k,v in zip(xrange(10), xrange(10,20))}

동안:

dict () 생성자는 튜플로 저장된 키-값 쌍 목록에서 직접 사전을 빌드합니다. 쌍이 패턴을 형성 할 때 목록 이해는 키-값 목록을 간결하게 지정할 수 있습니다.

tel = dict([('sape', 4139), ('guido', 4127), ('jack', 4098)]) {'sape': 4139, 'jack': 4098, 'guido': 4127}
data = dict((k,v) for k,v in zip(xrange(10), xrange(10,20)))

키가 간단한 문자열 인 경우 키워드 인수를 사용하여 쌍을 지정하는 것이 더 쉬운 경우가 있습니다.

dict(sape=4139, guido=4127, jack=4098)
>>>  {'sape': 4139, 'jack':4098, 'guido': 4127}

따라서 {}와 dict ()는 사전을 생성하지만 약간 다른 사전 데이터 초기화 방법을 제공합니다.


3

dict 리터럴 d = {'one': '1'}이 물건 값을 할당하고 데이터를 보내는 대신 훨씬 더 읽기 쉬운 정의 데이터를 찾습니다 .dict() 생성자 .

반면에 사람들이 dict 리터럴을 잘못 입력하는 것을 보았습니다. d = {'one', '1'} 이 현대 파이썬 2.7 이상에서 세트를 만들 .

그럼에도 불구하고 나는 여전히 리터럴을 사용하는 것을 선호합니다. 왜냐하면 더 읽기 쉽고 개인적인 취향을 생각하기 때문입니다.


나는 sets 의 리터럴 구문이 존재 한다는 것을 정기적으로 잊어 버립니다 . 나는 주문한 dicts에 문자 그대로의 구문이 있었으면 좋겠다.
ArtOfWarfare

2

dict () 리터럴은 다른 값을 붙여 넣을 때 (파이썬 없음) 환경 변수 목록과 같이 좋습니다. bash 파일이 있다면

FOO='bar'
CABBAGE='good'

dict()리터럴에 쉽게 붙여넣고 주석을 추가 할 수 있습니다 . 또한 반대의 작업을 더 쉽게하고 다른 것으로 복사합니다. 반면 {'FOO': 'bar'}구문 파이썬 및 JSON 꽤 독특합니다. 따라서 json을 많이 사용 {}하면 큰 따옴표와 함께 리터럴 을 사용할 수 있습니다 .


2

dict 상속 클래스, 추가 메소드가있는 사용자 정의 dict 클래스를 작성하는 dict 리터럴은 없습니다. 이 경우 사용자 정의 dict 클래스 생성자를 사용해야합니다. 예를 들면 다음과 같습니다.

class NestedDict(dict):

    # ... skipped

state_type_map = NestedDict(**{
    'owns': 'Another',
    'uses': 'Another',
})

0

또한 연산자와 일치하는 토큰을 생성자 구문 (예 : 대시 키)에서 사용할 수 없다는 사실을 고려하십시오.

>>> dict(foo-bar=1)
File "<stdin>", line 1
SyntaxError: keyword can't be an expression

>>> {'foo-bar': 1}
{'foo-bar': 1}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.