2013-05-08 3 views
34

나는이처럼 보이는 defaultdict 있습니다. 여기에서 발견 한 해결책 중 하나는 람다 대신 모듈 수준의 함수를 사용하는 것입니다. 제 질문은 모듈 수준의 기능이란 무엇입니까? 사전을 cPickle과 함께 사용하려면 어떻게해야합니까?피클 할 수 없음은 defaultdict

답변

40

Martijn's explanation 행 :

모듈 레벨 함수는이 아닌 수단 모듈 레벨에서 정의되는 함수이며 클래스의 인스턴스 메서드이며, 다른 함수 내에 중첩되지 않으며 람다 함수가 아닌 이름이있는 "실제"함수입니다.

그래서, 당신의 defaultdict 피클 대신 람다 함수의 모듈 수준의 기능을 만들려면 다음

def dd(): 
    return defaultdict(int) 

dict1 = defaultdict(dd) # dd is a module-level function 

당신이 그것을 나는 현재 비슷한 일을하고 있어요

tmp = pickle.dumps(dict1) # no exception 
new = pickle.loads(tmp) 
11

Pickle은 모든 인스턴스 속성을 저장하려고하며 defaultdict 인스턴스는 default 호출 가능 항목에 대한 참조를 저장합니다. Pickle은 각 인스턴스 속성에 대해 반복됩니다.

피클은 람다를 처리 할 수 ​​없습니다. 피클은 코드가 아닌 데이터 만 처리하며 람다는 코드를 포함합니다. 함수 일 수 있지만 함수가 일 때만 클래스 정의와 마찬가지로을 가져올 수 있습니다. 모듈 수준에서 정의 된 함수를 가져올 수 있습니다. pickle은 그 경우 문자열을 저장하며, 다시 읽지 않을 때 가져오고 참조 할 함수의 전체 '경로'만 저장합니다.

7

넌 단이 달성 partial을 사용할 수

또한
>>> from collections import defaultdict 
>>> from functools import partial 
>>> pickle.loads(pickle.dumps(defaultdict(partial(defaultdict, int)))) 
defaultdict(<functools.partial object at 0x94dd16c>, {}) 
+1

나에게 어떻게 풀 수 있습니까? 나는 호기심을 가지고 ... – Fred

1

피클보다 그러나 질문에 poser, default_factory로 사용되는 멤버 함수가있는 defaultdict 하위 클래스를 사용하고 있습니다. 내 코드가 제대로 작동하려면 (런타임에 정의 할 함수가 필요했습니다) 피클 링을위한 객체를 준비하는 코드를 추가했습니다.

대신에 :

.... 
factory = dict.default_factory 
dict.default_factory = None 
pickle.dump(dict, file) 
dict.default_factory = factory 
... 

이 내 트리로 사용되는 정확한 코드가 아닙니다가 같은 나무의 유형으로의 인스턴스를 생성하는 객체입니다

... 
pickle.dump(dict, file) 
... 

나는이 사용 인덱스가 요청됩니다 (이전/피클 작업을 수행하는 재귀 멤버 함수를 사용합니다). 그러나이 패턴도 질문에 응답합니다.

+0

절인 된 dict의 'default_factory'를 잃어 버리지 않으려는 경우에만 유용합니다. 공장을 더 이상 필요로하지 않는다면 간단히 'None'으로 설정하고 끝내면됩니다 (: – drevicko

5

이렇게하려면 쓰기를 원하는 코드를 작성하십시오. lambdas와 defaultdicts를 serialize 할 수있는 dill을 사용합니다. Dill은 파이썬에서 거의 모든 것을 직렬화 할 수 있습니다.

>>> import dill 
>>> from collections import defaultdict 
>>> 
>>> dict1 = defaultdict(lambda: defaultdict(int)) 
>>> pdict1 = dill.dumps(dict1) 
>>> _dict1 = dill.loads(pdict1) 
>>> _dict1 
defaultdict(<function <lambda> at 0x10b31b398>, {}) 
+0

). 이것은 dict1을 임시 파일에 덤프하고 다시로드하는 방법이 있습니까? –

+0

물론'dill'은'pickle'에서'dump'와'load'처럼 사용할 수있는 일반적인'dump'와'load'를 제공합니다. 'NamedTemporaryFile'에 덤프하는'dill.temp.dump'를 확인하고 싶습니다. –

+0

고맙습니다. 내 프로필의 최신 질문을 확인하십시오. 거기에 답변을 게시 할 수 있습니다. :) –

1

당신이 defaultdict 유형을 보존 걱정하지 않는 경우, 변환 :

fname = "file.pkl" 

for value in nested_default_dict: 
    nested_default_dict[value] = dict(nested_default_dict[value]) 
my_dict = dict(nested_default_dict) 

with open(fname, "wb") as f: 
    pickle.dump(my_dict, f) # Now this will work 

을 나는 이것이 당신이 산세 때부터 훌륭한 대안이라고 생각, 목적은 최종 형태의에 아마 ... 그리고, 다시 defaultdict 타입이 필요하다면, 다시 픽크 백 후에 다시 변환 할 수 있습니다 :

for value in my_dict: 
    my_dict[value] = defaultdict(type, my_dict[value]) 
nested_default_dict = defaultdict(type, my_dict)