[python] ‘setdefault’dict 메소드의 사용 사례

collections.defaultdictPython 2.5에 추가 하면 dictsetdefault메소드에 대한 필요성이 크게 줄어 들었습니다 . 이 질문은 우리의 집단 교육을위한 것입니다.

  1. setdefault오늘날 Python 2.6 / 2.7에서 여전히 유용한 것은 무엇입니까 ?
  2. 어떤 일반적인 사용 사례 setdefault로 대체 collections.defaultdict되었습니까?


답변

당신이 말할 수는 defaultdict설정 기본값에 유용 DICT를 작성하기 전에setdefault기본값을 설정하는 데 유용 동안 또는 DICT를 작성 후 .

아마도 가장 일반적인 유스 케이스 : 항목 그룹화 (정렬되지 않은 데이터, 그렇지 않으면 사용 itertools.groupby)

# really verbose
new = {}
for (key, value) in data:
    if key in new:
        new[key].append( value )
    else:
        new[key] = [value]


# easy with setdefault
new = {}
for (key, value) in data:
    group = new.setdefault(key, []) # key might exist already
    group.append( value )


# even simpler with defaultdict 
from collections import defaultdict
new = defaultdict(list)
for (key, value) in data:
    new[key].append( value ) # all keys have a default already

때로는 dict를 만든 후 특정 키가 있는지 확인하려고합니다. defaultdict이 경우 명시 적 액세스에서만 키를 생성하기 때문에 작동하지 않습니다. 많은 헤더와 함께 HTTP를 사용한다고 생각하십시오. 일부는 선택 사항이지만 기본값을 원합니다.

headers = parse_headers( msg ) # parse the message, get a dict
# now add all the optional headers
for headername, defaultvalue in optional_headers:
    headers.setdefault( headername, defaultvalue )


답변

setdefault이 함수와 같이 키워드 인수 dicts에 일반적으로 사용 합니다.

def notify(self, level, *pargs, **kwargs):
    kwargs.setdefault("persist", level >= DANGER)
    self.__defcon.set(level, **kwargs)
    try:
        kwargs.setdefault("name", self.client.player_entity().name)
    except pytibia.PlayerEntityNotFound:
        pass
    return _notify(level, *pargs, **kwargs)

키워드 인수를 취하는 함수 주위의 래퍼에서 인수를 조정하는 데 좋습니다.


답변

defaultdict 새 목록처럼 기본값이 정적 일 때 좋지만 동적 인 경우에는 그다지 많지 않습니다.

예를 들어 문자열을 고유 한 정수로 매핑하려면 사전이 필요합니다. defaultdict(int)항상 기본값으로 0을 사용합니다. 마찬가지로 defaultdict(intGen())항상 1을 생성합니다.

대신, 나는 정규 dict을 사용했습니다.

nextID = intGen()
myDict = {}
for lots of complicated stuff:
    #stuff that generates unpredictable, possibly already seen str
    strID = myDict.setdefault(myStr, nextID())

참고 dict.get(key, nextID())나중에뿐만 아니라이 값을 참조 할 수 있어야하기 때문에 불충분하다.

intGen int를 자동으로 증가시키고 그 값을 반환하는 작은 클래스입니다.

class intGen:
    def __init__(self):
        self.i = 0

    def __call__(self):
        self.i += 1
    return self.i

누군가 이것을 할 수있는 방법이 있다면 defaultdict그것을보고 싶습니다.


답변

setdefault()에서 기본값을 원할 때 사용 합니다 OrderedDict. 두 가지 를 모두 수행하는 표준 Python 컬렉션은 없지만 이러한 컬렉션을 구현 하는 방법 이 있습니다.


답변

대부분의 답변 상태 setdefault또는 defaultdict키가 존재하지 않을 때 기본값을 설정할 수 있습니다. 그러나의 사용 사례와 관련하여 작은주의 사항을 지적하고 싶습니다 setdefault. 파이썬 인터프리터가 실행될 때 setdefault키가 사전에 존재하더라도 항상 함수에 대한 두 번째 인수를 평가합니다. 예를 들면 다음과 같습니다.

In: d = {1:5, 2:6}

In: d
Out: {1: 5, 2: 6}

In: d.setdefault(2, 0)
Out: 6

In: d.setdefault(2, print('test'))
test
Out: 6

보시다시피 print, 사전에 2가 이미 존재하더라도 실행되었습니다. setdefault예를 들어와 같은 최적화 에 사용하려는 경우 특히 중요합니다 memoization. 에 대한 두 번째 인수로 재귀 함수 호출을 추가하면 setdefault파이썬이 항상 함수를 재귀 적으로 호출하므로 성능을 얻지 못합니다.

메모가 언급되었으므로 메모로 함수를 향상시키는 것을 고려하는 경우 functools.lru_cache 데코레이터를 사용하는 것이 더 나은 대안입니다. lru_cache는 재귀 함수에 대한 캐싱 요구 사항을보다 잘 처리합니다.


답변

Muhammad가 말했듯이 때때로 기본값을 설정하려는 상황이 있습니다. 이에 대한 좋은 예는 데이터 구조가 먼저 채워지고 쿼리됩니다.

트라이를 고려하십시오. 단어를 추가 할 때 하위 노드가 필요하지만 존재하지 않는 경우 트리를 확장하기 위해 하위 노드를 만들어야합니다. 단어의 존재를 쿼리 할 때 누락 된 하위 노드는 해당 단어가 존재하지 않으며 단어를 만들지 않아야 함을 나타냅니다.

defaultdict는 이것을 할 수 없습니다. 대신 get 및 setdefault 메소드를 사용하는 일반 dict를 사용해야합니다.


답변

이론적으로 말하면 때로는 기본값을 설정하고 때로는하지 않으려는 setdefault경우 여전히 유용합니다 . 실생활에서는 그런 유스 케이스를 보지 못했습니다.

그러나 흥미로운 사용 사례는 표준 라이브러리 (Python 2.6, _threadinglocal.py)에서 나옵니다.

>>> mydata = local()
>>> mydata.__dict__
{'number': 42}
>>> mydata.__dict__.setdefault('widgets', [])
[]
>>> mydata.widgets
[]

나는 사용 __dict__.setdefault이 꽤 유용한 경우 라고 말할 것 입니다.

편집 : 발생하는 것처럼 이것은 표준 라이브러리의 유일한 예이며 주석입니다. 따라서의 존재를 정당화하는 것만으로는 충분하지 않을 수 있습니다 setdefault. 여전히 여기에 설명이 있습니다.

객체는 속성에 속성을 저장 __dict__합니다. 그와 같이, __dict__속성은 객체 생성 후 언제든지 쓸 수 있습니다. 또한 사전이 아닙니다 defaultdict. 일반적인 경우의 객체가 가지고하는 것은 분별없는 __dict__A와 defaultdict그 속성과 모든 법적 식별자를 가진 각 개체를 만들 것 때문이다. 따라서 __dict__.setdefault유용하지 않은 것으로 간주되면 완전히 삭제하는 것 외에는 제거하는 Python 객체의 변경을 예측할 수 없습니다 .