[PYTHON] 파이썬 dict : get 대 setdefault
PYTHON파이썬 dict : get 대 setdefault
다음 두 표현은 나에게 동등한 것처럼 보입니다. 어느 것이 더 낫습니까?
data = [('a', 1), ('b', 1), ('b', 2)]
d1 = {}
d2 = {}
for key, val in data:
# variant 1)
d1[key] = d1.get(key, []) + [val]
# variant 2)
d2.setdefault(key, []).append(val)
결과는 동일하지만 어떤 버전이 더 좋거나 훨씬 더 파이썬적인가요?
개인적으로 나는 버전 2를 이해하기가 더 힘들다는 것을 알았고, 나는 setdefault를 이해하기가 매우 까다 롭다. 내가 올바르게 이해하면 사전에 "key"의 값을 찾는다. 사용할 수 없다면 "[]"를 입력하고, 값이나 "[]"에 대한 참조를 반환하고 "val"에 그 값을 덧붙인다. 참고. 확실히 부드럽지만 적어도 (적어도 나에게는) 직관적이지 않습니다.
내 마음에, 버전 1 이해하기 쉽습니다 (가능하다면, "키"에 대한 값을 얻지 못하면 "[]"을 얻고, [val]로 구성된 목록에 가입하고 그 결과를 "키" ). 그러나 이해하기가 더 직관적이지만,이 목록이 생성되면서이 버전이 덜 효과적 일 수 있습니다. 또 다른 단점은 "d1"이 오류가 발생하기 쉬운 표현에서 두 번 발생한다는 것입니다. 아마 get을 사용하는 것이 더 나은 구현이지만, 현재는 그것을 벗어날 수 있습니다.
내 생각에 버전 2는 경험이 부족한 사람들을 파악하기가 더 어렵지만 더 빠르고 더 바람직합니다. 의견?
해결법
-
==============================
1.당신의 두 예제는 똑같은 일을하지만 get과 setdefault가하는 것을 의미하지는 않습니다.
당신의 두 예제는 똑같은 일을하지만 get과 setdefault가하는 것을 의미하지는 않습니다.
둘의 차이점은 기본적으로 d [key]가 매번 목록을 가리 키도록 수동으로 설정하는 것과는 달리 setdefault는 설정되지 않은 경우에만 d [key]를 목록에 자동으로 설정합니다.
가능한 두 가지 방법을 비슷하게 만들어서 실행했습니다.
from timeit import timeit print timeit("c = d.get(0, []); c.extend([1]); d[0] = c", "d = {1: []}", number = 1000000) print timeit("c = d.get(1, []); c.extend([1]); d[0] = c", "d = {1: []}", number = 1000000) print timeit("d.setdefault(0, []).extend([1])", "d = {1: []}", number = 1000000) print timeit("d.setdefault(1, []).extend([1])", "d = {1: []}", number = 1000000)
그리고있어.
0.794723378711 0.811882272256 0.724429205999 0.722129751973
따라서 setdefault는이 목적을 달성하는 것보다 약 10 % 빠릅니다.
get 메소드를 사용하면 setdefault를 사용하여 할 수있는 것보다 적은 작업을 수행 할 수 있습니다. 키를 설정하지 않으려는 경우에도 키가 존재하지 않을 때 KeyError가 발생하지 않도록 할 수 있습니다 (키 이벤트가 자주 발생하는 경우).
'setdefault'dict 메쏘드의 유스 케이스를 보시오. dict.get () 메쏘드는 두 메쏘드에 대한 더 많은 정보를위한 포인터를 반환합니다.
setdefault에 대한 스레드는 대부분의 경우 defaultdict를 사용하려고한다고 결론 내립니다. get에 관한 스레드는 느린 것으로 결론을 내리고 종종 double lookup, defaultdict 사용 또는 오류 처리 (사전 크기 및 사용 사례에 따라 다름)를 사용하는 것이 좋습니다.
-
==============================
2.Agf로부터받은 대답은 좋아하는 것과 비슷하지 않습니다. 후:
Agf로부터받은 대답은 좋아하는 것과 비슷하지 않습니다. 후:
print timeit("d[0] = d.get(0, []) + [1]", "d = {1: []}", number = 10000)
d [0]은 10,000 개의 항목이있는 목록을 포함하는 반면,
print timeit("d.setdefault(0, []) + [1]", "d = {1: []}", number = 10000)
d [0]은 단순히 []입니다. 즉, d.setdefault 버전은 d에 저장된 목록을 수정하지 않습니다. 코드는 실제로 다음과 같아야합니다.
print timeit("d.setdefault(0, []).append(1)", "d = {1: []}", number = 10000)
실제로 잘못된 setdefault 예제보다 빠릅니다.
여기서 차이점은 연결을 사용하여 추가 할 때마다 전체 목록이 복사 될 때마다 (그리고 측정 할 수있는 요소가 10,000 개가되면 일단 업데이트됩니다.) append를 사용하면 목록 업데이트가 O (1)로 상각됩니다. 즉 효과적으로 일정 시간입니다.
마지막으로, 원래 질문에서 고려되지 않은 두 가지 옵션이 있습니다. 즉, defaultdict 또는 단순히 키가 들어 있는지 여부를 확인하기 위해 사전을 테스트하는 것입니다.
따라서, d3을 가정하면, d4 = defaultdict (list), {}
# variant 1 (0.39) d1[key] = d1.get(key, []) + [val] # variant 2 (0.003) d2.setdefault(key, []).append(val) # variant 3 (0.0017) d3[key].append(val) # variant 4 (0.002) if key in d4: d4[key].append(val) else: d4[key] = [val]
변형 1은 매번 목록을 복사하기 때문에 가장 느립니다. 변형 2는 두 번째로 느립니다. 변형 3은 가장 빠르지 만 2.5보다 오래된 Python이 필요하고 변형 4가 변형 3보다 약간 느리면 작동하지 않습니다. .
가능한 경우 변형 3을 사용하고, 변형 4는 defaultdict가 정확한 적합이 아닌 가끔 장소에 대한 옵션으로 사용한다고 말합니다. 원본 변형 모두를 피하십시오.
-
==============================
3.collections 모듈에서 defaultdict를 보길 원할 것입니다. 다음은 예제와 동일합니다.
collections 모듈에서 defaultdict를 보길 원할 것입니다. 다음은 예제와 동일합니다.
from collections import defaultdict data = [('a', 1), ('b', 1), ('b', 2)] d = defaultdict(list) for k, v in data: d[k].append(v)
여기에 더 많은 것이 있습니다.
-
==============================
4.1. 좋은 예를 들면 다음과 같습니다 : http://code.activestate.com/recipes/66516-add-an-entry-to-a-dictionary-unless-the-entry-is-a/
1. 좋은 예를 들면 다음과 같습니다 : http://code.activestate.com/recipes/66516-add-an-entry-to-a-dictionary-unless-the-entry-is-a/
2. 더 많은 설명 : http://python.net/~goodger/projects/pycon/2007/idiomatic/handout.html
dict.setdefault ()는 get 또는 set & get과 동일합니다. 또는 필요한 경우 설정하십시오. 사전 키의 계산이나 입력이 오래 걸리는 경우 특히 효율적입니다.
dict.setdefault ()의 유일한 문제점은 필요 여부에 상관없이 항상 기본값이 평가된다는 것입니다. 기본값은 계산하는 데 비용이 많이 드는 경우에만 중요합니다. 이 경우 defaultdict를 사용하십시오.
3. 마지막으로 차이가있는 공식 문서가 http://docs.python.org/2/library/stdtypes.html로 강조 표시되었습니다.
setdefault (key [, default]) 키가 사전에 있으면 해당 값을 반환합니다. 그렇지 않은 경우 key를 default 값으로 입력하고 default를 리턴하십시오. 기본값은 None입니다.
-
==============================
5.
In [1]: person_dict = {} In [2]: person_dict['liqi'] = 'LiQi' In [3]: person_dict.setdefault('liqi', 'Liqi') Out[3]: 'LiQi' In [4]: person_dict.setdefault('Kim', 'kim') Out[4]: 'kim' In [5]: person_dict Out[5]: {'Kim': 'kim', 'liqi': 'LiQi'} In [8]: person_dict.get('Dim', '') Out[8]: '' In [5]: person_dict Out[5]: {'Kim': 'kim', 'liqi': 'LiQi'}
-
==============================
6.dict.get의 논리는 다음과 같습니다.
dict.get의 논리는 다음과 같습니다.
if key in a_dict: value = a_dict[key] else: value = default_value
예를 들면 다음과 같습니다.
In [72]: a_dict = {'mapping':['dict', 'OrderedDict'], 'array':['list', 'tuple']} In [73]: a_dict.get('string', ['str', 'bytes']) Out[73]: ['str', 'bytes'] In [74]: a_dict.get('array', ['str', 'byets']) Out[74]: ['list', 'tuple']
setdefault의 메커니즘은 다음과 같습니다.
levels = ['master', 'manager', 'salesman', 'accountant', 'assistant'] #group them by the leading letter group_by_leading_letter = {} # the logic expressed by obvious if condition for level in levels: leading_letter = level[0] if leading_letter not in group_by_leading_letter: group_by_leading_letter[leading_letter] = [level] else: group_by_leading_letter[leading_letter].append(word) In [80]: group_by_leading_letter Out[80]: {'a': ['accountant', 'assistant'], 'm': ['master', 'manager'], 's': ['salesman']}
setdefault dict 메소드는 정확하게이 목적을위한 것입니다. 앞의 for 루프는 다음과 같이 다시 작성할 수 있습니다.
In [87]: for level in levels: ...: leading = level[0] ...: group_by_leading_letter.setdefault(leading,[]).append(level) Out[80]: {'a': ['accountant', 'assistant'], 'm': ['master', 'manager'], 's': ['salesman']}
매우 간단합니다. null이 아닌 목록에 요소를 추가하거나 null 목록에 요소를 추가하는 것을 의미합니다.
defaultdict는 더 쉽게 만듭니다. 하나를 만들려면 dict의 각 슬롯에 대한 기본값을 생성하는 유형 또는 함수를 전달합니다.
from collections import defualtdict group_by_leading_letter = defaultdict(list) for level in levels: group_by_leading_letter[level[0]].append(level)
-
==============================
7.아직이 두 용어를 이해하는데 어려움을 겪고있는 사람들을 위해 get ()과 setdefault () 메소드의 기본적인 차이점을 설명하겠습니다.
아직이 두 용어를 이해하는데 어려움을 겪고있는 사람들을 위해 get ()과 setdefault () 메소드의 기본적인 차이점을 설명하겠습니다.
시나리오 -1
root = {} root.setdefault('A', []) print(root)
시나리오 -2
root = {} root.get('A', []) print(root)
시나리오 -1에서는 시나리오 2에서 { 'A': []}이 출력됩니다 {}
따라서 setdefault ()는 dict에 부재 키를 설정하지만 get ()은 기본값 만 제공하지만 사전은 수정하지 않습니다.
이제 이것이 유용 할 곳으로 가자. 당신이 값이리스트 인 dict 내의 엘리먼트를 검색하고 있다고 가정한다면 그리스트를 수정하고자한다면 그리스트를 가지고 새로운 키를 생성하라.
setdefault () 사용
def fn1(dic, key, lst): dic.setdefault(key, []).extend(lst)
get ()를 사용하여
def fn2(dic, key, lst): dic[key] = dic.get(key, []) + (lst) #Explicit assigning happening here
이제 타이밍을 검사 할 수 있습니다.
dic = {} %%timeit -n 10000 -r 4 fn1(dic, 'A', [1,2,3])
288 ns 걸렸습니다.
dic = {} %%timeit -n 10000 -r 4 fn2(dic, 'A', [1,2,3])
128 초 남았습니다.
따라서이 두 가지 접근 방식에는 매우 큰 타이밍 차이가 있습니다.
from https://stackoverflow.com/questions/7423428/python-dict-get-vs-setdefault by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] 하위 프로세스에서 읽을 수있는 임시 파일을 만드는 방법은 무엇입니까? (0) | 2018.10.25 |
---|---|
[PYTHON] Tkinter 창이 열리는 위치를 지정하는 방법? (0) | 2018.10.25 |
[PYTHON] Python MySQLdb : connection.close () VS. cursor.close () (0) | 2018.10.25 |
[PYTHON] Python Selenium에서 속성으로 요소를 찾는 방법이 있습니까? (0) | 2018.10.25 |
[PYTHON] Python try finally 블록 반환 [duplicate] (0) | 2018.10.25 |