我在python 3.7中使用莳萝,但是当我重新加载后者时,该函数的属性之一丢失了。
我有一个名为session的类,该类在程序退出时保存,并在启动时加载。该对象间接包含Tranform
个实例,这些实例具有引用特定功能的function
属性。该函数具有一些属性。
在保存会话时使用调试器时,可以看到存在特定属性,并将其设置为None
。但是,当我加载一个已保存的会话时,除了该一个属性已消失之外,一切都很好。
这是保存代码:
def save(self):
print ('\n SAVING SESSION STATE, DO NOT EXIT')
breakpoint()
sessionDirectory='__PETL__'
if not os.path.exists(sessionDirectory):
os.makedirs(sessionDirectory)
with open(sessionDirectory+'/'+self.name, 'wb') as f:
dill.dump(self,f)
print ('\nSession Saved, exiting')
这是加载代码:
def loadSession(self, sessionName):
if (Session.dontLoad):
print ('Creating New Session')
return None
try:
with open('__PETL__/'+ sessionName, 'rb') as f:
session=dill.load(f)
except FileNotFoundError:
print ('No session found, creating new one')
return None
return session
这是调试器的输出:
保存:
> /home/osboxes/stage/inspireDataBase2/migrations/src/session/session.py(160)save()
-> sessionDirectory='__PETL__'
(Pdb) print( self.transforms[0].transform.function.queryRes)
None
(Pdb) print (dir(self.transforms[0].transform.function)[-9:])
['after', 'args', 'columns', 'fetch', 'indexs', 'query', 'queryRes', 'sameorderasafter', 'transformvar']
(Pdb) dill.dumps(self.transforms[0].transform.function)
b'\x80\x03cuserTransformModulePreparsed\ntransform__constru__buildinggeometry2d\nq\x00.'
(Pdb) c
Session Saved, exiting
正在加载:
> /home/osboxes/stage/inspireDataBase2/migrations/src/session/session.py(39)__init__()
-> session.printJobDone()
(Pdb) print( self.transforms[0].transform.function.queryRes)
*** AttributeError: 'function' object has no attribute 'queryRes'
(Pdb) print( session.transforms[0].transform.function.queryRes)
*** AttributeError: 'function' object has no attribute 'queryRes'
(Pdb) print (dir(session.transforms[0].transform.function)[-9:])
['__subclasshook__', 'after', 'args', 'columns', 'fetch', 'indexs', 'query', 'sameorderasafter', 'transformvar']
如您所见,其他属性按预期工作。
由于节省部分是我在项目中要做的最后一件事,我想我只是不了解莳萝是如何工作的。该属性彼此不同,因为该属性设置在另一个类中(而不是与该函数位于同一模块中)。其他属性直接在功能模块中设置。也就是说,该模块是通过编译AST树获得的,但我不明白为什么会出现问题。
我看到确实在第一个输出中,莳萝输出中只引用了该函数的模块(但是我不知道莳萝是如何工作的,也许这很正常)。
答案 0 :(得分:1)
dill
不能捕获函数属性,不能捕获可以直接导入的函数。可能是在导入时,通过其他代码将您在加载时看到的所有属性添加到了该功能对象。
dill.dumps()
存储的所有信息足以重新导入相同的功能对象。在userTransformModulePreparsed.transform__constru__buildinggeometry2d
的调试会话中。加载该序列化时,只需完成import userTransformModulePreparsed
,然后使用该模块的transform__constru__buildinggeometry2d
属性即可。在这种情况下,函数被视为 singletons ,每个Python进程仅需要存在一个副本。假定该对象的所有加载均由正常的import
处理。这包括添加到函数对象的属性!
dill
可以处理生成的函数对象,即,任何不能直接导入的函数对象,届时它将捕获所有功能的各个方面,包括属性。例如,每次调用父函数时,在函数(嵌套函数)中使用def
总是会创建一个新的单独的函数对象。序列化此类对象的处理方式不同:
>>> import dill
>>> def foo():
... def bar(): pass # nested function
... bar.spam = 'ham'
... return bar
...
>>> foo()
<function foo.<locals>.bar at 0x110621e50>
>>> foo() is not foo() # new calls produce new function objects
True
>>> bar = foo()
>>> vars(bar) # the resulting function object has attributes
{'spam': 'ham'}
>>> bar_restored = dill.loads(dill.dumps(bar))
>>> vars(bar_restored) # the attributes are preserved by dill
{'spam': 'ham'}
>>> bar.extra = 'additional'
>>> vars(dill.loads(dill.dumps(bar))) # this extends to new attributes added later.
{'spam': 'ham', 'extra': 'additional'}
因此,您在这里有两个选择;要么在导入时设置function属性,要么或在嵌套函数中生成函数。