Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python pathlib.Path的子类对象在pickle.load之后丢失自定义属性_Python_Python 3.x_Inheritance_Serialization_Pickle - Fatal编程技术网

Python pathlib.Path的子类对象在pickle.load之后丢失自定义属性

Python pathlib.Path的子类对象在pickle.load之后丢失自定义属性,python,python-3.x,inheritance,serialization,pickle,Python,Python 3.x,Inheritance,Serialization,Pickle,我正在创建一个子类pathlib.Path,并想向它添加一些自定义属性。 问题是,自定义属性在被pickle重新加载后丢失。 如何解决这个问题 我尝试过的其他解决方案: 使用\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,同样的问题 使用组合而不是继承,然后通过实现\uu getattr\uu来分派类似路径的方法。但是,在这种情况下,self.path未在pickle.load中初始化,从而导致对\uuuuuu getattr\uuuuu的无休止调用 一种方法是使用模

我正在创建一个子类
pathlib.Path
,并想向它添加一些自定义属性。 问题是,自定义属性在被pickle重新加载后丢失。 如何解决这个问题

我尝试过的其他解决方案:

  • 使用
    \uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
    ,同样的问题
  • 使用组合而不是继承,然后通过实现
    \uu getattr\uu
    来分派类似路径的方法。但是,在这种情况下,
    self.path
    未在
    pickle.load
    中初始化,从而导致对
    \uuuuuu getattr\uuuuu
    的无休止调用

一种方法是使用模块将pickle支持函数关联到类的实例,如下所示。注意,我还必须修改
P
类处理参数的方式-它不再忽略这些参数

class File():
    def __init__(self, *args):
        self.path = Path(*args)
    def __getattr__(self, item):
        return getattr(self.path, item)
p = File('aaa')
p.exists()  # no error
with open('xx', 'wb') as wf:
    pickle.dump(p, wf)
p1 = pickle.load(open('xx', 'rb')) 
# RecursionError: maximum recursion depth exceeded. 
# This is due to call of self.path, in that moment, path is not in self.__dict__
输出:

import copyreg
from pathlib import Path
import pickle


class P(type(Path())):
    def __init__(self, *args):
        super().__init__()
        self.a = args[0] if args else ''


def pickle_P(p):
    print("pickling a P instance...")
    return P, (p.a,)

copyreg.pickle(P, pickle_P)

p = P()
p.a = 'x'
q = P('y')

with open('xx', 'wb') as outp:
    pickle.dump(p, outp)
    pickle.dump(q, outp)

with open('xx', 'rb') as inp:
    p1 = pickle.load(inp)
    q1 = pickle.load(inp)

print('p1.a = {!r}'.format(p1.a))
print('q1.a = {!r}'.format(q1.a))
关于继承的问题。 另一个解决方案作为@martineau答案的注释

如果我是正确的,那么问题是由
pathlib.PosixPath
中的
\uuu reduce\uuu
方法引起的。似乎酸洗行为将由该方法确定。使用
copyreg.pickle(P,pickle\u P)
的@martineau的解决方案也与此方法相关:
pickle\u P
具有与
\uuuu\uu
相同的返回模式

以下是关于返回值的单据:

返回元组时,元组的长度必须介于两到六项之间。 可选项可以省略,也可以不提供任何项作为其选项 价值每个项目的语义顺序如下:

  • 将被调用以创建对象初始版本的可调用对象

  • 可调用对象的参数元组。如果可调用对象不接受任何参数,则必须提供空元组

  • (可选)对象的状态,如前所述,该状态将传递给对象的
    \uuuu setstate\uuu()
    方法。如果对象没有这样的方法,那么该值必须是一个字典,并将其添加 到对象的
    \uuuu dict\uuuu
    属性

第二项说明@martineau的解决方案是如何工作的:第二个返回值将被传递到
\uuuu init\uuuu

这是PosixPath的源代码

def\uuuuuuuuuuuuuuuuuu(自):
#使用零件元组有助于共享内部路径零件
#当酸洗相关路径时。
#self.\u parts是传递给路径的参数
return(self.\uuuuu类,tuple(self.\u部分))
根据第三个返回值的描述,解决方案是:

从pathlib导入路径
进口泡菜
类P(类型(路径()):
定义初始化(self,*args):
super()。\uuuu init\uuuuu()
self.a=''
定义减少(自):
返回self.\u类、元组(self.\u部分)、self.\u dict__
p=p()
p、 a='x'
以open('xx','wb')作为wf:
泡菜倾倒区(p、wf)
p1=pickle.load(打开('xx','rb'))
打印(p1.a)#这里p1.a是“x”
此解决方案的缺点:

  • P的实例将包含一个
    \uuuuu dict\uuu
    属性(
    Path
    使用
    \uuuu slots\uu
  • 名为
    \u hash
    的属性将被忽略
对于作文的问题,一个 的文档中的注释可以解释错误的原因

请注意,在取消勾选时,一些方法,如
\uu getattr\uu()
, 可以在实例上调用
\uuuu getattribute\uuuuuuuuuuuuuuuuuuuuu()
\uuuuuuuuuu setattr\uuuuuuuuuuuuuuuuuu()
。如果这些方法依赖于某个内部不变量为真,则 类型应该实现
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
取消勾选实例时,不会调用
\uuuu init\uuu()

要确保调用
\uuuuuu getattr\uuuuuuu
path
属性退出,一个解决方案是将属性分配移动到
\uuuuuuu new\uuuuuu
方法中(在
\uuuuu init\uuuuuuu
之前)

class文件():
定义新(cls,*参数):
obj=super()。\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuux(cls)
obj.path=path(*args)
返回obj
def _uGetAttr _;(自身,项目):
返回getattr(self.path,item)
p=文件('aaa')
p、 exists()#无错误
以open('xx','wb')作为wf:
泡菜倾倒区(p、wf)
p1=pickle.load(打开('xx','rb')#无错误

合成版怎么样?如果该错误也可以通过这种方式解决。我检查了
copyreg
的文档,但是没有说明如何编写支持函数。正如我所说,这是一种方法。首先,helper函数可以以不同的方式实现,另外还有其他类似的方法,根本不涉及使用
copyreg
模块。我不太清楚你所说的作曲是什么意思。如果这是一个重要的方面,请在您的问题中提及并添加(更好的)描述。谢谢,我指的是第二个代码示例中的情况。我认为组合方法的问题在于知道(或以某种方式确定)已将哪些属性添加到实例中,以便通过
pickle
保存和稍后还原这些属性。我并不是说我认为这是不可能的,但我仍然不清楚你到底想完成什么,更不用说为什么必须以某种方式完成。我试图创建一个与
pathlib.Path
具有相同接口的类。哇,nvm,我倒过来了
import copyreg
from pathlib import Path
import pickle


class P(type(Path())):
    def __init__(self, *args):
        super().__init__()
        self.a = args[0] if args else ''


def pickle_P(p):
    print("pickling a P instance...")
    return P, (p.a,)

copyreg.pickle(P, pickle_P)

p = P()
p.a = 'x'
q = P('y')

with open('xx', 'wb') as outp:
    pickle.dump(p, outp)
    pickle.dump(q, outp)

with open('xx', 'rb') as inp:
    p1 = pickle.load(inp)
    q1 = pickle.load(inp)

print('p1.a = {!r}'.format(p1.a))
print('q1.a = {!r}'.format(q1.a))
pickling a P instance...
pickling a P instance...
p1.a = 'x'
q1.a = 'y'