使用 Dill 加载对象的 Python TypeError

Posted

技术标签:

【中文标题】使用 Dill 加载对象的 Python TypeError【英文标题】:Python TypeError on Load Object using Dill 【发布时间】:2014-08-28 00:06:13 【问题描述】:

试图将一个大且(可能非常)不可拾取的对象渲染到文件中以供以后使用。

dill.dump(file) 方面没有投诉:

In [1]: import echonest.remix.audio as audio

In [2]: import dill

In [3]: audiofile = audio.LocalAudioFile("/Users/path/Track01.mp3")
en-ffmpeg -i "/Users/path/audio/Track01.mp3" -y -ac 2 -ar 44100 "/var/folders/X2/X2KGhecyG0aQhzRDohJqtU+++TI/-Tmp-/tmpWbonbH.wav"
Computed MD5 of file is b3820c166a014b7fb8abe15f42bbf26e
Probing for existing analysis

In [4]: with open('audio_object_dill.pkl', 'wb') as f:
   ...:     dill.dump(audiofile, f)
   ...:  

In [5]: 

但试图加载.pkl 文件:

In [1]: import dill

In [2]: with open('audio_object_dill.pkl', 'rb') as f:
   ...:     audio_object = dill.load(f)
   ...:  

返回以下错误:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-2-203b696a7d73> in <module>()
      1 with open('audio_object_dill.pkl', 'rb') as f:
----> 2     audio_object = dill.load(f)
      3 

/Users/mikekilmer/Envs/GLITCH/lib/python2.7/site-packages/dill-0.2.2.dev-py2.7.egg/dill/dill.pyc in load(file)
    185     pik = Unpickler(file)
    186     pik._main_module = _main_module
--> 187     obj = pik.load()
    188     if type(obj).__module__ == _main_module.__name__: # point obj class to main
    189         try: obj.__class__ == getattr(pik._main_module, type(obj).__name__)

/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.pyc in load(self)
    856             while 1:
    857                 key = read(1)
--> 858                 dispatch[key](self)
    859         except _Stop, stopinst:
    860             return stopinst.value

/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/pickle.pyc in load_newobj(self)
   1081         args = self.stack.pop()
   1082         cls = self.stack[-1]
-> 1083         obj = cls.__new__(cls, *args)
   1084         self.stack[-1] = obj
   1085     dispatch[NEWOBJ] = load_newobj

TypeError: __new__() takes at least 2 arguments (1 given)

AudioObject 比上面调用的class object 复杂得多(而且大得多)(来自SO answer),我不清楚是否需要通过dill 发送第二个参数,如果是,那么该参数是什么,或者如何判断任何酸洗方法是否适用于该特定对象。

稍微检查一下对象本身:

In [4]: for k, v in vars(audiofile).items():
...:     print k, v
...: 

返回:

is_local False
defer False
numChannels 2
verbose True
endindex 13627008
analysis <echonest.remix.audio.AudioAnalysis object at 0x103c61bd0>
filename /Users/mikekilmer/Envs/GLITCH/glitcher/audio/Track01.mp3
convertedfile /var/folders/X2/X2KGhecyG0aQhzRDohJqtU+++TI/-Tmp-/tmp9ADD_Z.wav
sampleRate 44100
data [[0 0]
 [0 0]
 [0 0]
 ..., 
 [0 0]
 [0 0]
 [0 0]]

audiofile.analysis 似乎包含一个名为audiofile.analysis.source 的属性,其中包含(或显然指向)audiofile.analysis.source.analysis

【问题讨论】:

更深入地探索文档 - 包含在 pypi.python.org/pypi/dill 我在docs.python.org/2/library/pickle.html 中读到“文件必须有两种方法”。也许我保存的文件只有一种方法,那就是缺少的第二个参数打破了cls.__new__(cls, *args) echonest API 是不是我可以在需要时拿来试用?无论如何,您可以尝试一些事情来发现正在发生的事情。首先,由于它是一个类,您可以尝试切换dill.dumps 中的byref,以切换“通过引用”对类进行酸洗。如果这不起作用,请尝试打开dill.detect.trace(True) 以查看(反)序列化中的内部检查点。您还可以查看dill.detect 中的方法,例如badobjects 可以帮助诊断正在发生的事情。 __getstate____setstate__ 看起来不匹配,这很奇怪。 是的,@MikeMcKerns。 echonest.com。通过developer.echonest.com 可以使用两个相关模块,我在mzoo.org/getting-the-python-echonest-remix-package-running 分享了该过程。 pypi.python.org/pypi/dill、trac.mystic.cacr.caltech.edu/project/pathos/wiki/dill 和 pickle 文档基本上是我应该查看的阅读材料的范围(在实施上述建议时)吗? 天哪,你在 pastebin 里有一个可怕的 trace。是的,很遗憾,这就是dill 上的所有阅读材料。顺便说一句,您应该尝试badobjects(audiofile, depth=1)——它可以让您深入研究每个对象,即使是失败的对象。另请查看此作为莳萝检测可以做什么的示例。 ***.com/questions/10082241/…***.com/questions/25241139/… 【参考方案1】:

在这种情况下,答案在于模块本身。

LocalAudioFile 类提供(并且它的每个实例都可以为此使用)它自己的 save 方法,通过 LocalAudioFile.save 或更可能是 the_audio_object_instance.save 调用。

.mp3 文件的情况下,LocalAudioFile 实例包含一个指向临时 .wav 文件的指针,该文件是 .mp3 的解压缩版本,以及一大堆分析数据在与(基于互联网的)Echonest API 接口之后,从初始音频文件返回。

LocalAudioFile.save 调用shutil.copyfile(path_to_wave, wav_path) 以保存与链接到音频对象的原始文件具有相同名称和路径的.wav 文件,如果文件已存在则返回错误。它调用pickle.dump(self, f) 将分析数据保存到一个文件,该文件也在调用初始音频对象文件的目录中。

LocalAudioFile 对象可以简单地通过 pickle.load() 重新引入。

这是一个iPython 会话,我在其中使用了dill,这是一个非常有用的包装器或接口,它提供了大多数标准pickle 方法以及更多:

audiofile = audio.LocalAudioFile("/Users/mikekilmer/Envs/GLITCH/glitcher/audio/Track01.mp3")

In [1]: import echonest.remix.audio as audio

In [2]: import dill
# create the audio_file object
In [3]: audiofile = audio.LocalAudioFile("/Users/mikekilmer/Envs/GLITCH/glitcher/audio/Track01.mp3")
en-ffmpeg -i "/Users/path/audio/Track01.mp3" -y -ac 2 -ar 44100 "/var/folders/X2/X2KGhecyG0aQhzRDohJqtU+++TI/-Tmp-/tmp_3Ei0_.wav"
Computed MD5 of file is b3820c166a014b7fb8abe15f42bbf26e
Probing for existing analysis
#call the LocalAudioFile save method
In [4]: audiofile.save()
Saving analysis to local file /Users/path/audio/Track01.mp3.analysis.en
#confirm the object is valid by calling it's duration method
In [5]: audiofile.duration
Out[5]: 308.96
#delete the object - there's probably a "correct" way to do this
in [6]: audiofile = 0
#confirm it's no longer an audio_object
In [7]: audiofile.duration
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-12-04baaeda53a4> in <module>()
----> 1 audiofile2.duration

AttributeError: 'int' object has no attribute 'duration'


#open the pickled version (using dill)
In [8]: with open('/Users/path/audio/Track01.mp3.analysis.en') as f:
   ....:     audiofile = dill.load(f)
   ....:     
#confirm it's a valid LocalAudioFile object
In [8]: audiofile.duration
Out[8]: 308.96

Echonest 是一个非常强大的 API,并且 remix 包提供了大量的功能。有一小部分相关链接集合here。

【讨论】:

我一直面临以下错误maximum recursion depth exceeded 正常吗?

以上是关于使用 Dill 加载对象的 Python TypeError的主要内容,如果未能解决你的问题,请参考以下文章

如何腌制“记忆化”的 Python 函数?

Python反射介绍

不小心替换了dtcms.model.dll 和 dtccms.web.dill 文件怎么办

12.python-metaclass元类

ImportError:无法加载指定的对象 - psycopg2

无法在 Python 中加载共享对象文件 [重复]