SO의 훌륭한 사람들 덕분 collections.defaultdict
에 가독성과 속도에서 제공하는 가능성을 발견했습니다 . 나는 그것들을 성공으로 사용했다.
이제 세 가지 수준의 사전을 구현하고 싶습니다. 두 가지 최상위 수준 defaultdict
과 가장 낮은 수준 int
입니다. 이 작업을 수행하는 적절한 방법을 찾지 못했습니다. 내 시도는 다음과 같습니다.
from collections import defaultdict
d = defaultdict(defaultdict)
a = [("key1", {"a1":22, "a2":33}),
("key2", {"a1":32, "a2":55}),
("key3", {"a1":43, "a2":44})]
for i in a:
d[i[0]] = i[1]
이제는 작동하지만 원하는 동작 인 다음은 작동하지 않습니다.
d["key4"]["a1"] + 1
나는 어딘가에 두 번째 레벨 defaultdict
이 type 이라고 선언해야한다고 생각 int
하지만 어디에서 어떻게 할 것인지 찾지 못했습니다.
내가 defaultdict
처음 사용하는 이유 는 각각의 새 키에 대한 사전을 초기화하지 않아도되기 때문입니다.
더 우아한 제안이 있습니까?
고마워 pythoneers!
답변
사용하다:
from collections import defaultdict
d = defaultdict(lambda: defaultdict(int))
defaultdict(int)
에서 새 키에 액세스 할 때마다 새로 작성 됩니다 d
.
답변
피클 가능하고 중첩 된 defaultdict를 만드는 또 다른 방법은 람다 대신 부분 객체를 사용하는 것입니다.
from functools import partial
...
d = defaultdict(partial(defaultdict, int))
defaultdict 클래스는 모듈 수준에서 전역 적으로 액세스 가능하기 때문에 작동합니다.
“랩핑하는 함수 (또는이 경우 클래스)가 전역 적으로 액세스 할 수없는 경우 __name__ 아래 (__module__ 내)에 부분 오브젝트를 피클 할 수 없습니다”- 랩핑 된 부분 함수
답변
보다 일반적인 해결책 은 nosklo의 답변을 참조하십시오 .
class AutoVivification(dict):
"""Implementation of perl's autovivification feature."""
def __getitem__(self, item):
try:
return dict.__getitem__(self, item)
except KeyError:
value = self[item] = type(self)()
return value
테스트 :
a = AutoVivification()
a[1][2][3] = 4
a[1][3][3] = 5
a[1][2]['test'] = 6
print a
산출:
{1: {2: {'test': 6, 3: 4}, 3: {3: 5}}}
답변
에 대한 @rschwieb의 요청에 따라 메소드 를 정의하여 추가를 재정 의하여 이전보다D['key'] += 1
확장하여 이를보다__add__
collections.Counter()
먼저 __missing__
빈 값을 새로 만들어서로 전달됩니다 __add__
. 빈 값을 계산하여 값을 테스트합니다 False
.
재정의에 대한 자세한 내용은 숫자 유형 에뮬레이션을 참조하십시오 .
from numbers import Number
class autovivify(dict):
def __missing__(self, key):
value = self[key] = type(self)()
return value
def __add__(self, x):
""" override addition for numeric types when self is empty """
if not self and isinstance(x, Number):
return x
raise ValueError
def __sub__(self, x):
if not self and isinstance(x, Number):
return -1 * x
raise ValueError
예 :
>>> import autovivify
>>> a = autovivify.autovivify()
>>> a
{}
>>> a[2]
{}
>>> a
{2: {}}
>>> a[4] += 1
>>> a[5][3][2] -= 1
>>> a
{2: {}, 4: 1, 5: {3: {2: -1}}}
인수가 숫자인지 확인하는 대신 (비 파이썬, amirite!) 기본 0 값을 제공 한 다음 작업을 시도 할 수 있습니다.
class av2(dict):
def __missing__(self, key):
value = self[key] = type(self)()
return value
def __add__(self, x):
""" override addition when self is empty """
if not self:
return 0 + x
raise ValueError
def __sub__(self, x):
""" override subtraction when self is empty """
if not self:
return 0 - x
raise ValueError
답변
파티에 늦었지만 임의의 깊이로 방금 다음과 같은 일을했습니다.
from collections import defaultdict
class DeepDict(defaultdict):
def __call__(self):
return DeepDict(self.default_factory)
여기서의 요령은 기본적으로 DeepDict
인스턴스 자체를 결 측값을 구성하는 유효한 팩토리로 만드는 것입니다. 이제 우리는 다음과 같은 일을 할 수 있습니다
dd = DeepDict(DeepDict(list))
dd[1][2].extend([3,4])
sum(dd[1][2]) # 7
ddd = DeepDict(DeepDict(DeepDict(list)))
ddd[1][2][3].extend([4,5])
sum(ddd[1][2][3]) # 9
답변
def _sub_getitem(self, k):
try:
# sub.__class__.__bases__[0]
real_val = self.__class__.mro()[-2].__getitem__(self, k)
val = '' if real_val is None else real_val
except Exception:
val = ''
real_val = None
# isinstance(Avoid,dict)也是true,会一直递归死
if type(val) in (dict, list, str, tuple):
val = type('Avoid', (type(val),), {'__getitem__': _sub_getitem, 'pop': _sub_pop})(val)
# 重新赋值当前字典键为返回值,当对其赋值时可回溯
if all([real_val is not None, isinstance(self, (dict, list)), type(k) is not slice]):
self[k] = val
return val
def _sub_pop(self, k=-1):
try:
val = self.__class__.mro()[-2].pop(self, k)
val = '' if val is None else val
except Exception:
val = ''
if type(val) in (dict, list, str, tuple):
val = type('Avoid', (type(val),), {'__getitem__': _sub_getitem, 'pop': _sub_pop})(val)
return val
class DefaultDict(dict):
def __getitem__(self, k):
return _sub_getitem(self, k)
def pop(self, k):
return _sub_pop(self, k)
In[8]: d=DefaultDict()
In[9]: d['a']['b']['c']['d']
Out[9]: ''
In[10]: d['a']="ggggggg"
In[11]: d['a']
Out[11]: 'ggggggg'
In[12]: d['a']['pp']
Out[12]: ''
다시 오류가 없습니다. 아무리 많은 레벨이 중첩 되더라도 팝도 오류 없음
dd = DefaultDict ({ “1”: 333333})