Error during unpickling in python. AttributeError: 'Airthematic' object has no attribute '__addition'

Error during unpickling in python. AttributeError: 'Airthematic' object has no attribute '__addition'

下面是示例代码,我pickle成功了,但是unpickling报错。任何人都知道原因或解决方案将不胜感激。

sample.py

import pandas as pd

class Airthematic(object):
    
    def __init__(self, symbol):
        self.symbol_ = symbol
        self.__x = None
        self.__y = None
        self.__result = None
        self.__function_mapping = {
            "+": self.__addition,
            "-": self.__subtraction,
            "*": self.__multiplication
        }
        
    def calculate(self, x, y):
        
        self.__x = x
        self.__y = y
        self.__result = self.__function_mapping[self.symbol_]()
    
    def __addition(self):
        return self.__x+self.__y
    
    def __subtraction(self):
        return self.__x-self.__y
    
    def __multiplication(self):
        return self.__x*self.__y

    @property
    def first_number_(self):
        return self.__x

    @property
    def second_number_(self):
        return self.__y

    @property
    def result_(self):
        return self.__result

这是juypter中的代码

from sample import Airthematic
a = Airthematic("+")
a.calculate(5, 6)
pd.to_pickle(a, "../output/sample.pickle") # Successful
aa = pd.read_pickle("../output/sample.pickle") # Giving error

    

AttributeError: 'Airthematic' 对象没有属性 '__addition'

不知何故包含函数映射的字典出错。

正如@IainShelvington 所解释的那样,私有属性和函数名称是不同的。所以我腌制后,用记事本打开文件观察了一下。我发现私有属性名保存为_Airthematic__x、_Airthematic__y等。但是函数名称没有存储,因为它存储为属性 _Airthematic__function_mapping 的 __multiplication。此外,在阅读@ewong 共享的文档后,我注意到函数名称未保存在 pickle 文件中。因此,当 unpickling 时,它会发现名为 __multiplication 的属性,该属性不存在于 pickle 文件中,因为未存储函数名称。所以我找到了解决方案,必须实现“__getstate__”和“__setstate__”功能。下面是修改后的版本,可以正常工作。

import pandas as pd

class Airthematic(object):
    
    def __init__(self, symbol):
        self.symbol_ = symbol
        self.__x = None
        self.__y = None
        self.__result = None
        self.__function_mapping = {
            "+": self.__addition,
            "-": self.__subtraction,
            "*": self.__multiplication
        }


    def __getstate__(self):

        state = self.__dict__.copy()

        # Remove the unpicklable entries.
        del state["_" + str(self.__class__.__name__) + '__function_mapping']
        return state


    def __setstate__(self, state):
        # Restore instance attributes (i.e., function_mapping).
        self.__dict__.update(state)
        self.__function_mapping = {
            "+": self.__addition,
            "-": self.__subtraction,
            "*": self.__multiplication
        }

        
    def calculate(self, x, y):
        
        self.__x = x
        self.__y = y
        self.__result = self.__function_mapping[self.symbol_]()
    
    def __addition(self):
        return self.__x+self.__y
    
    def __subtraction(self):
        return self.__x-self.__y
    
    def __multiplication(self):
        return self.__x*self.__y

    @property
    def first_number_(self):
        return self.__x

    @property
    def second_number_(self):
        return self.__y

    @property
    def result_(self):
        return self.__result