>  기사  >  백엔드 개발  >  Python의 defaultdict에 대한 자세한 설명(코드 예)

Python의 defaultdict에 대한 자세한 설명(코드 예)

不言
不言앞으로
2018-10-25 17:34:433155검색

이 기사는 Python의 defaultdict에 대한 자세한 설명(코드 예제)을 제공합니다. 이는 특정 참조 가치가 있으므로 도움이 될 수 있습니다.

기본값은 매우 편리할 수 있습니다

우리 모두 알고 있듯이 Python에서는 사전에 존재하지 않는 키에 액세스하면 KeyError 예외가 발생합니다(JavaScript에서는 속성이 존재하지 않는 경우). 객체에 존재하는 경우 정의되지 않음이 반환됩니다). 그러나 때로는 사전의 모든 키에 대해 기본값을 갖는 것이 매우 편리합니다. 예를 들어 다음 예는 다음과 같습니다.

strings = ('puppy', 'kitten', 'puppy', 'puppy',
           'weasel', 'puppy', 'kitten', 'puppy')
counts = {}
for kw in strings:
    counts[kw] += 1

이 예는 문자열에 단어가 나타나는 횟수를 계산하고 이를 counts 사전에 기록합니다. 단어가 나타날 때마다 개수에 해당하는 키에 저장된 값이 1씩 증가합니다. 그러나 실제로 이 코드를 실행하면 KeyError 예외가 발생합니다. Python 명령줄에서 확인할 수 있는 Python 사전에는 기본값이 없기 때문에 각 단어가 처음으로 계산될 때 발생합니다.

판단문을 사용하여 확인

이 경우 가장 먼저 생각할 수 있는 방법은 단어가 처음 계산될 때 해당 키에 기본값 1을 저장하는 것입니다. 이를 위해서는 처리 중에 판단문을 추가해야 합니다:
>>> counts = dict()
>>> counts
{}
>>> counts['puppy'] += 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: &#39;puppy&#39;

dict.setdefault() 메서드를 사용하세요

dict.setdefault() 메서드를 통해 기본값을 설정할 수도 있습니다:

strings = (&#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;, &#39;puppy&#39;,
           &#39;weasel&#39;, &#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;)
counts = {}
for kw in strings:
    if kw not in counts:
        counts[kw] = 1
    else:
        counts[kw] += 1
# counts:
# {&#39;puppy&#39;: 5, &#39;weasel&#39;: 1, &#39;kitten&#39;: 2}

dict.setdefault에서 수신 () 메소드 두 개의 매개변수, 첫 번째 매개변수는 키의 이름이고 두 번째 매개변수는 기본값입니다. 주어진 키가 사전에 없으면 매개변수에 제공된 기본값이 반환되고, 그렇지 않으면 사전에 저장된 값이 반환됩니다. dict.setdefault() 메소드의 반환 값을 사용하면 for 루프의 코드를 더 간결하게 다시 작성할 수 있습니다.


strings = (&#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;, &#39;puppy&#39;,
           &#39;weasel&#39;, &#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;)
counts = {}
for kw in strings:
    counts.setdefault(kw, 0)
    counts[kw] += 1

collections.defaultdict 클래스를 사용하세요

위의 메소드로 문제가 해결되지 않지만 dict의 기본값에 대해 어느 정도 질문이 있지만 이 시점에서 우리는 궁금해할 것입니다. 자체적으로 기본값의 기능을 제공하는 사전이 있습니까? 대답은 '예'입니다. collections.defaultdict입니다.

defaultdict 클래스는 dict와 비슷하지만 다음 유형으로 초기화됩니다.

strings = (&#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;, &#39;puppy&#39;,
           &#39;weasel&#39;, &#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;)
counts = {}
for kw in strings:
    counts[kw] = counts.setdefault(kw, 0) + 1

defaultdict 클래스의 초기화 함수는 유형을 매개변수로 허용합니다. 액세스되는 키가 존재하지 않으면 값이 인스턴스화될 수 있습니다. 기본값 :

>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> dd
defaultdict(<type &#39;list&#39;>, {})

이 기본값 형식은 dict[key] 또는 dict.__getitem__(key)를 통해 액세스할 때만 유효하다는 점에 유의해야 합니다. 그 이유는 아래에서 소개하겠습니다.

>>> dd[&#39;foo&#39;]
[]
>>> dd
defaultdict(<type &#39;list&#39;>, {&#39;foo&#39;: []})
>>> dd[&#39;bar&#39;].append(&#39;quux&#39;)
>>> dd
defaultdict(<type &#39;list&#39;>, {&#39;foo&#39;: [], &#39;bar&#39;: [&#39;quux&#39;]})
dict[key]或者dict.__getitem__(key)访问的时候才有效,这其中的原因在下文会介绍。

>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> &#39;something&#39; in dd
False
>>> dd.pop(&#39;something&#39;)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: &#39;pop(): dictionary is empty&#39;
>>> dd.get(&#39;something&#39;)
>>> dd[&#39;something&#39;]
[]

该类除了接受类型名称作为初始化函数的参数之外,还可以使用任何不带参数的可调用函数,到时该函数的返回结果作为默认值,这样使得默认值的取值更加灵活。下面用一个例子来说明,如何用自定义的不带参数的函数zero()作为初始化函数的参数:

>>> from collections import defaultdict
>>> def zero():
...     return 0
...
>>> dd = defaultdict(zero)
>>> dd
defaultdict(<function zero at 0xb7ed2684>, {})
>>> dd[&#39;foo&#39;]
0
>>> dd
defaultdict(<function zero at 0xb7ed2684>, {&#39;foo&#39;: 0})

利用collections.defaultdict来解决最初的单词统计问题,代码如下:

from collections import defaultdict
strings = (&#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;, &#39;puppy&#39;,
           &#39;weasel&#39;, &#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;)
counts = defaultdict(lambda: 0)  # 使用lambda来定义简单的函数
for s in strings:
    counts[s] += 1

defaultdict 类是如何实现的

通过上面的内容,想必大家已经了解了defaultdict类的用法,那么在defaultdict类中又是如何来实现默认值的功能呢?这其中的关键是使用了看__missing__()这个方法:

>>> from collections import defaultdict
>>> print defaultdict.__missing__.__doc__
__missing__(key) # Called by __getitem__ for missing key; pseudo-code:
  if self.default_factory is None: raise KeyError(key)
  self[key] = value = self.default_factory()
  return value

通过查看__missing__()方法的docstring,可以看出当使用__getitem__()方法访问一个不存在的键时(dict[key]这种形式实际上是__getitem__()方法的简化形式),会调用__missing__()方法获取默认值,并将该键添加到字典中去。

关于__missing__()方法的具体介绍可以参考Python官方文档中的"Mapping Types — dict"一节。

文档中介绍,从2.5版本开始,如果派生自dict的子类定义了__missing__()方法,当访问不存在的键时,dict[key]会调用__missing__()方法取得默认值。

从中可以看出,虽然dict支持__missing__()方法,但是在dict本身是不存在这个方法的,而是需要在派生的子类中自行实现这个方法。可以简单的验证这一点:

>>> print dict.__missing__.__doc__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object &#39;dict&#39; has no attribute &#39;__missing__&#39;

同时,我们可以进一步的做实验,定义一个子类Missing并实现__missing__()方法:

>>> class Missing(dict):
...     def __missing__(self, key):
...         return 'missing'
...
>>> d = Missing()
>>> d
{}
>>> d['foo']
'missing'
>>> d
{}

返回结果反映了__missing__()方法确实发挥了作用。在此基础上,我们稍许修改__missing__()方法,使得该子类同defautldict类一样为不存在的键设置一个默认值:

>>> class Defaulting(dict):
...     def __missing__(self, key):
...         self[key] = &#39;default&#39;
...         return &#39;default&#39;
...
>>> d = Defaulting()
>>> d
{}
>>> d[&#39;foo&#39;]
&#39;default&#39;
>>> d
{&#39;foo&#39;: &#39;default&#39;}

在旧版本的 Python 中实现 defaultdict 的功能

defaultdict类是从2.5版本之后才添加的,在一些旧版本中并不支持它,因此为旧版本实现一个兼容的defaultdict类是必要的。这其实很简单,虽然性能可能未必如2.5版本中自带的defautldict类好,但在功能上是一样的。

首先,__getitem__()方法需要在访问键失败时,调用__missing__()方法:

class defaultdict(dict):
    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)

其次,需要实现__missing__()方法用来设置默认值:

class defaultdict(dict):
    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)
    def __missing__(self, key):
        self[key] = value = self.default_factory()
        return value

然后,defaultdict类的初始化函数__init__() 유형 이름을 초기화 함수의 매개변수로 허용하는 것 외에도 이 클래스는 매개변수 없이 호출 가능한 모든 함수를 사용할 수도 있습니다. 함수의 반환 결과가 기본값으로 사용되므로 기본값이 더 유연해집니다. . 다음은 매개변수 없이 사용자 정의 함수 zero()를 초기화 함수의 매개변수로 사용하는 방법을 보여주는 예입니다.

class defaultdict(dict):
    def __init__(self, default_factory=None, *a, **kw):
        dict.__init__(self, *a, **kw)
        self.default_factory = default_factory    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)
    def __missing__(self, key):
        self[key] = value = self.default_factory()
        return value
🎜초기 단어 통계 문제를 해결하려면 collections.defaultdict를 사용하세요. :🎜
try:
    from collections import defaultdictexcept ImportError:
    class defaultdict(dict):
      def __init__(self, default_factory=None, *a, **kw):
          dict.__init__(self, *a, **kw)
          self.default_factory = default_factory      def __getitem__(self, key):
          try:
              return dict.__getitem__(self, key)
          except KeyError:
              return self.__missing__(key)

      def __missing__(self, key):
          self[key] = value = self.default_factory()
          return value
🎜defaultdict 클래스 구현 방법🎜🎜위 내용을 통해 defaultdict 클래스의 사용법을 이해하셨을 텐데, defaultdict 클래스에서 기본값 함수를 어떻게 구현하나요? 이에 대한 핵심은 __missing__() 메서드를 사용하는 것입니다: 🎜rrreee🎜 __missing__() 메서드의 독스트링을 보면 __getitem__() 메서드를 사용하여 존재하지 않는 키(dict[key)에 액세스할 때를 볼 수 있습니다. ] 이 형식은 실제로 기본값을 얻고 사전에 키를 추가하기 위해 __missing__() 메서드를 호출하는 __getitem__() 메서드의 단순화된 형식입니다. 🎜🎜 __missing__() 메서드에 대한 자세한 소개는 공식 Python 문서의 "매핑 유형 — dict" 섹션을 참조하세요. 🎜🎜 문서에 따르면 버전 2.5부터 dict에서 파생된 하위 클래스가 __missing__() 메서드를 정의하는 경우 존재하지 않는 키에 액세스할 때 dict[key]는 기본값을 얻기 위해 __missing__() 메서드를 호출합니다. 🎜🎜이를 통해 dict가 __missing__() 메서드를 지원하지만 이 메서드는 dict 자체에 존재하지 않고 대신 파생 하위 클래스에서 구현되어야 함을 알 수 있습니다. 이는 쉽게 확인할 수 있습니다: 🎜rrreee🎜동시에 추가 실험을 수행하고 Missing 하위 클래스를 정의하고 __missing__() 메서드를 구현할 수 있습니다. 🎜rrreee🎜 반환 결과는 __missing__() 메서드가 작동한다는 것을 반영합니다. 이를 바탕으로 이 하위 클래스가 defautldict 클래스와 같이 존재하지 않는 키에 대한 기본값을 설정하도록 __missing__() 메서드를 약간 수정합니다. 🎜rrreee🎜 defaultdict의 함수는 Python의 이전 버전에서 구현됩니다🎜 defaultdict 클래스는 다음과 같습니다. 파생 버전 2.5 이후에 추가되었으며 일부 이전 버전에서는 지원되지 않으므로 이전 버전에 대해 호환되는 defaultdict 클래스를 구현해야 합니다. 이는 실제로 매우 간단합니다. 비록 성능이 버전 2.5에 포함된 defautldict 클래스만큼 좋지 않을 수도 있지만 기능적으로는 동일합니다. 🎜먼저, 액세스 키가 실패할 때 __getitem__() 메서드는 __missing__() 메서드를 호출해야 합니다. 🎜rrreee🎜두 번째로, 기본값을 설정하려면 __missing__() 메서드를 구현해야 합니다. 🎜 rrreee🎜그런 다음 defaultdict 클래스 __init__()의 초기화 함수는 유형 또는 호출 가능한 함수 매개변수를 허용해야 합니다. 🎜
class defaultdict(dict):
    def __init__(self, default_factory=None, *a, **kw):
        dict.__init__(self, *a, **kw)
        self.default_factory = default_factory    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)
    def __missing__(self, key):
        self[key] = value = self.default_factory()
        return value

最后,综合以上内容,通过以下方式完成兼容新旧Python版本的代码:

try:
    from collections import defaultdictexcept ImportError:
    class defaultdict(dict):
      def __init__(self, default_factory=None, *a, **kw):
          dict.__init__(self, *a, **kw)
          self.default_factory = default_factory      def __getitem__(self, key):
          try:
              return dict.__getitem__(self, key)
          except KeyError:
              return self.__missing__(key)

      def __missing__(self, key):
          self[key] = value = self.default_factory()
          return value

위 내용은 Python의 defaultdict에 대한 자세한 설명(코드 예)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 csdn.net에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제