2013-02-03 6 views
1

pickle을 사용하여 맞춤 클래스를 저장하려고합니다. 아래의 코드와 매우 비슷합니다 (클래스에 정의 된 몇 가지 메소드 및 데이터에 대한 몇 가지 더 많은 dicts 등). 그러나 종종이 작업을 실행하고 pickle을 누른 다음 unpickle을 수행하면 클래스에있는 데이터가 모두 손실되고 새로운 빈 인스턴스가 만들어진 것처럼 처리됩니다.가끔씩 비어있는 객체를 만듭니다.

import pickle 
class MyClass: 
    VERSION = 1 
    some_data = {} 
    more_data = set() 

    def save(self,filename): 
     with open(filename, 'wb') as f: 
      p = pickle.Pickler(f) 
      p.dump(self) 

    def load(filename): 
     with open(filename,'rb') as ifile: 
      u = pickle.Unpickler(ifile) 
      obj = u.load() 
      return obj 

이것이 피클 클래스의 메모와 관련이 있는지 궁금해했지만 필자는 그렇게 느끼지 않았습니다. 난이 충분히 희망, (분명히 읽을 수있는 것을 의미하지,하지만 분명히 어떤 데이터도 포함하지 않는다) 어쨌든

 
€c__main__ 
MyClass 
q

을 : 작동하지 않을 때, 내 생성 된 파일을보고는 다음과 같이 보입니다 누군가 여기서 일어날 일이 무엇인지, 무엇을보아야하는지 이해해야합니다.

+1

코드를'pickle.dumps'와'pickle.loads' 사이에서 바꿀 수 있습니까? 왜냐하면 pickle 프로토콜은 코드 변경에 탄력적이라고 ​​생각하지 않기 때문입니다. –

+0

클래스에서 [pickle 프로토콜] (http://docs.python.org/2/library/pickle.html#pickle-protocol)을 구현하여 제대로 작동하는지 확인해야합니다. – Wessie

+0

인스턴스 데이터를'some_data' 및'more_data' 클래스 변수에 저장하고 있습니까? 그것들은 인스턴스 자체의 일부가 아니기 때문에'pickle '에 의해 저장되지 않습니다. 클래스에 저장하는 것이 아니라'__init__' 메쏘드로 만들어야합니다. – Blckknght

답변

6

문제는 데이터를 인스턴스 변수에 저장하는 대신 변경 가능한 클래스 변수를 사용하여 데이터를 보관하는 것입니다.

pickle 모듈은 인스턴스에 직접 저장된 데이터 만 저장하며, self을 통해 액세스 할 수있는 클래스 변수는 저장하지 않습니다. unpickled 인스턴스에 데이터가 없다는 것을 알게되면 클래스가 이전 실행의 데이터를 보유하지 않으므로 더 이상 인스턴스에 액세스 할 수 없습니다.

그런 식으로 클래스 변수를 사용하면 데이터가 클래스의 모든 인스턴스에서 공유되므로 다른 문제도 발생할 수 있습니다! 다음은 문제를 설명하는 Python 콘솔 세션 코드입니다.

>>> class Foo(object): 
     class_var = [] 
     def __init__(self, value): 
      self.class_var.append(value) 

>>> f1 = Foo(1) 
>>> f1.class_var 
[1] 
>>> f2 = Foo(2) 
>>> f2.class_var 
[1, 2] 

아마도 원하는 것이 아닙니다. 그러나 그것은 더 나 빠졌다!

>>> f1.class_var 
[1, 2] 

당신이 f1 소유했다고 생각 데이터는 f2의 생성에 의해 변경되었습니다. 실제로 f1.class_varf2.class_var과 동일한 객체입니다 (어떤 인스턴스도 전혀 거치지 않고 Foo.class_var을 통해 직접 사용할 수 있습니다).

그래서 클래스 변수를 사용하면 거의 원하는 것이 아닙니다. 예상대로

>>> class Bar(object): 
     def __init__(self, value): 
      self.instance_var = [] # creates a separate list for each instance! 
      self.instance_var.append(value) 

>>> b1 = Bar(1) 
>>> b1.instance_var 
[1] 
>>> b2 = Bar(2) 
>>> b2.instance_var # doesn't include value from b1 
[2] 
>>> b1.instance_var # b1's data is unchanged 
[1] 

피클이 클래스를 처리하는 대신, 새로운 가치를 창출하고 인스턴스 변수로 저장 클래스에 대한 __init__ 방법을 쓰기. 모든 데이터가 인스턴스에 있으므로 unpickle 때 빈 인스턴스로 끝나지 않아야합니다.

관련 문제