복붙노트

[PYTHON] namedtuple 인스턴스를 올바르게 피클 링하는 법

PYTHON

namedtuple 인스턴스를 올바르게 피클 링하는 법

나는 피클을 사용하는 법을 배우고있다. namedtuple 객체를 생성하고 목록에 추가 한 다음 해당 목록을 피클 링하려고했습니다. 그러나 다음과 같은 오류가 발생합니다.

pickle.PicklingError: Can't pickle <class '__main__.P'>: it's not found as __main__.P

함수 안에 배치하지 않고 코드를 실행하면 완벽하게 작동한다는 것을 알게되었습니다. 함수 내에서 래핑 될 때 객체를 피클하는 데 필요한 추가 단계가 있습니까?

여기 내 코드가 있습니다 :

from collections import namedtuple
import pickle

def pickle_test():
    P = namedtuple("P", "one two three four")
    my_list = []
    abe = P("abraham", "lincoln", "vampire", "hunter")
    my_list.append(abe)
    f = open('abe.pickle', 'w')
    pickle.dump(abe, f)
    f.close()

pickle_test()

해결법

  1. ==============================

    1.함수 밖에서 명명 된 튜플을 만듭니다.

    함수 밖에서 명명 된 튜플을 만듭니다.

    from collections import namedtuple
    import pickle
    
    P = namedtuple("P", "one two three four")
    
    def pickle_test():
        my_list = []
        abe = P("abraham", "lincoln", "vampire", "hunter")
        my_list.append(abe)
        f = open('abe.pickle', 'w')
        pickle.dump(abe, f)
        f.close()
    
    pickle_test()
    

    이제 피클은 그것을 찾을 수 있습니다. 지금은 글로벌 모듈입니다. unpickling 할 때 모든 pickle 모듈은 __main __.P를 다시 찾습니다. 귀하의 버전에서, P는 로컬이며, pickle_test () 함수에 대한 것이고, 그것은 내성적이거나 수입 가능하지 않습니다.

    namedtuple ()은 클래스 팩토리임을 기억해야합니다. 당신은 그것에게 매개 변수를주고 여러분이 인스턴스를 만들 수있는 클래스 객체를 리턴합니다. pickle은 인스턴스에 포함 된 데이터와 원래의 클래스에 대한 문자열 참조 만 저장하여 인스턴스를 다시 재구성합니다.

  2. ==============================

    2.주된 대답에 대한 의견으로 내 질문을 추가 한 후에 동적으로 생성 된 명명 된 튜플 피클 가능 문제를 해결하는 방법을 발견했습니다. 이것은 (DB 쿼리 후) 런타임 동안 필드를 발견하고 있기 때문에 필자의 경우에 필요합니다.

    주된 대답에 대한 의견으로 내 질문을 추가 한 후에 동적으로 생성 된 명명 된 튜플 피클 가능 문제를 해결하는 방법을 발견했습니다. 이것은 (DB 쿼리 후) 런타임 동안 필드를 발견하고 있기 때문에 필자의 경우에 필요합니다.

    내가하는 일은 namedtuple을 효과적으로 __main__ 모듈로 옮겨서 원숭이 패치를하는 것뿐입니다.

    def _CreateNamedOnMain(*args):
        import __main__
        namedtupleClass = collections.namedtuple(*args)
        setattr(__main__, namedtupleClass.__name__, namedtupleClass)
        namedtupleClass.__module__ = "__main__"
        return namedtupleClass
    

    주의하지 않으면 명명 된 튜플 이름 (args에 의해 제공됨)이 __main__의 다른 멤버를 덮어 쓸 수 있음을 명심하십시오.

  3. ==============================

    3.또는 cloudpickle 또는 dill을 사용하여 직렬화 할 수 있습니다.

    또는 cloudpickle 또는 dill을 사용하여 직렬화 할 수 있습니다.

    from collections import namedtuple
    
    import cloudpickle
    import dill
    
    
    
    def dill_test(dynamic_names):
        P = namedtuple('P', dynamic_names)
        my_list = []
        abe = P("abraham", "lincoln", "vampire", "hunter")
        my_list.append(abe)
        with open('deleteme.cloudpickle', 'wb') as f:
            cloudpickle.dump(abe, f)
        with open('deleteme.dill', 'wb') as f:
            dill.dump(abe, f)
    
    
    dill_test("one two three four")
    
  4. ==============================

    4.다른 스레드에서이 대답을 발견했습니다. 이것은 명명 된 튜플의 명명에 관한 것입니다. 이것은 나를 위해 일했다 :

    다른 스레드에서이 대답을 발견했습니다. 이것은 명명 된 튜플의 명명에 관한 것입니다. 이것은 나를 위해 일했다 :

    group_t =            namedtuple('group_t', 'field1, field2')  # this will work
    mismatched_group_t = namedtuple('group_t', 'field1, field2')  # this will throw the error
    
  5. ==============================

    5.여기서 문제는 자식 프로세스가 객체 클래스를 가져올 수 없다는 것입니다.이 경우 P 클래스입니다. 다중 모델 프로젝트의 경우 클래스 P는 자식 프로세스가 사용되는 곳이면 어디서나 가져올 수 있어야합니다.

    여기서 문제는 자식 프로세스가 객체 클래스를 가져올 수 없다는 것입니다.이 경우 P 클래스입니다. 다중 모델 프로젝트의 경우 클래스 P는 자식 프로세스가 사용되는 곳이면 어디서나 가져올 수 있어야합니다.

    빠른 해결 방법은 globals ()에 영향을줌으로써 importable하게하는 것입니다.

    globals()["P"] = P
    
  6. from https://stackoverflow.com/questions/16377215/how-to-pickle-a-namedtuple-instance-correctly by cc-by-sa and MIT license