Python defaultdictモジュールとnamedtupleモジュール

5317 ワード

Pythonにはint,str,list,tuple,dictなどの内蔵データ型がある.Pythonのcollectionsモジュールは、これらの内蔵データ型に基づいて、namedtuple、defaultdict、deque、Counter、OrderedDictなど、いくつかの追加のデータ型を提供しています.defaultdictとnamedtupleは2つの実用的な拡張タイプです.defaultdictはdictから継承され、namedtupleはtupleから継承されます.
一、defaultdict
1.概要
Pythonオリジナルのデータ構造dictを使用する場合、d[key]のようにアクセスすると、指定したkeyが存在しない場合、KeyError異常が投げ出されます.ただし、defaultdictを使用すると、デフォルトのファクトリメソッドを入力すると、存在しないkeyが要求されると、このファクトリメソッドはその結果を呼び出してこのkeyのデフォルト値として使用されます.
defaultdictは使用時にファクトリ関数(function_factory)を渡す必要があります.defaultdict(function_factory)は、デフォルト値を持つdictのようなオブジェクトを構築します.デフォルト値はファクトリ関数を呼び出すことによって生成されます.
2.例
次にdefaultdictの使用例を示します.
>>> from collections import defaultdict
>>> s = [('xiaoming', 99), ('wu', 69), ('zhangsan', 80), ('lisi', 96), ('wu', 100), ('wu', 100), ('yuan', 98), ('xiaoming', 89)]
>>> d = defaultdict(list)
>>> for k, v in s:
...     d[k].append(v)
... 
>>> d
defaultdict(, {'lisi': [96], 'xiaoming': [99, 89], 'yuan': [98], 'zhangsan': [80], 'wu': [69, 100, 100]})
>>> for k,v in d.items():
...     print '%s: %s' % (k, v)
... 
lisi: [96]
xiaoming: [99, 89]
yuan: [98]
zhangsan: [80]
wu: [69, 100, 100]
>>> 


Pythonに詳しい学生はdefaultdict(list)の使い方がdict.setdefault(key,[])と似ていることを発見することができます.上記のコードはsetdefaultを使用して以下のように実現されています.
>>> s
[('xiaoming', 99), ('wu', 69), ('zhangsan', 80), ('lisi', 96), ('wu', 100), ('wu', 100), ('yuan', 98), ('xiaoming', 89)]
>>> d = {}
>>> for k,v in s:
...     d.setdefault(k, []).append(v)
... 
>>> d
{'lisi': [96], 'xiaoming': [99, 89], 'yuan': [98], 'zhangsan': [80], 'wu': [69, 100, 100]}


3.原理
以上の例からdefaultdictの使い方を基本的に理解することができ、次にhelp(defaultdict)でdefaultdictの原理を理解することができます.Python consoleで印刷されたhelp情報を見ると、defaultdictにデフォルト値があるのは主にmissingメソッドで実現されていることがわかります.ファクトリ関数がNoneでない場合、ファクトリメソッドでデフォルト値を返します.具体的には、次のとおりです.
>>> help(defaultdict)
 |  __missing__(...)
 |      __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メソッドはgetitemメソッドを呼び出してKEYが存在しないことを発見したときに呼び出されるので、defaultdictもd[key]またはd.getitem(key)を使用する場合にのみデフォルト値を生成します.d.get(key)を使用してもデフォルト値は返されない場合、KeyErrorが表示されます.
  • defaultdictは主にmissing法によって実現されるので,この方法を実現することによって独自のdefaultdict
  • を生成することもできる.
    4.バージョン
    defaultdictはPython 2.5以降に加わった機能で、旧バージョンのPythonではこの機能はサポートされていませんが、その原理を知って、私たちは自分でdefaultdictを実現することができます.
    try:
        from collections import defaultdict
    except:
        class defaultdict(dict):
    
            def __init__(self, default_factory=None, *a, **kw):
                if (default_factory is not None and not hasattr(default_factory, '__call__')):
                    raise TypeError('first argument must be callable')
                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):
                if self.default_factory is None:
                    raise KeyError(key)
                self[key] = value = self.default_factory()
                return value
    
            def __reduce__(self):
                if self.default_factory is None:
                    args = tuple()
                else:
                    args = self.default_factory,
                return type(self), args, None, None, self.items()
    
            def copy(self):
                return self.__copy__()
    
            def __copy__(self):
                return type(self)(self.default_factory, self)
    
            def __deepcopy__(self, memo):
                import copy
                return type(self)(self.default_factory, copy.deepcopy(self.items()))
    
            def __repr__(self):
                return 'defaultdict(%s, %s)' % (self.default_factory, dict.__repr__(self))
    
    

    二、namedtuple
    namedtupleは主に、要素に名前でアクセスできるデータオブジェクトを生成するために使用され、通常はコードの可読性を向上させるために使用され、いくつかのtupleタイプのデータにアクセスする際に特に便利です.実際には、ほとんどの場合、tupleの代わりにnamedtupleを使用する必要があります.これにより、コードが読みやすくなり、pythonicになります.例を挙げます.
    from collections import namedtuple
    
    #     namedtuple             ,       
    Student = namedtuple('Student', 'id name score')
    #    Student = namedtuple('Student', ['id', 'name', 'score'])
    
    students = [(1, 'Wu', 90), (2, 'Xing', 89), (3, 'Yuan', 98), (4, 'Wang', 95)]
    
    for s in students:
        stu = Student._make(s)
        print stu
    
    # Output:
    # Student(id=1, name='Wu', score=90)
    # Student(id=2, name='Xing', score=89)
    # Student(id=3, name='Yuan', score=98)
    # Student(id=4, name='Wang', score=95)
    
    

    上記の例では、Studioはnamedtupleであり、tupleの使用方法と同様にindexで直接取ることができ、読み取り専用である.この方式はtupleよりずっと理解しやすく,各値が表す意味をよく知ることができる.
    Over!