Python pickle 实例没有属性
Python pickle instance has no attribute
我正在尝试抓取网站。在这个网站中,我将抓取的人存储在 person_set 中,将抓取下一个人的队列存储在 parse_queue 中。在每人爬行开始的时候,我需要把这两个数据结构写到一个文件中,以防爬行因为异常或者网络不好而中断,以便后面继续。
我有三个 python 文件。一个主文件、一个蜘蛛和一个人模型。 Main实例化spider,spider开始解析,必要时调用write和read。 person 文件有 class Person,它是存储人物数据的模型。
我在读取我写入的数据时遇到问题。我检查了很多关于这个错误的问题,它似乎是一个导入问题。但是即使我将 Person class 导入到 main 和 spiders 中,它仍然给我错误。似乎 emergency_read 方法不受我的顶级导入的影响。
main.py
from spiders import Spider
from person import Person
import pickle
def main():
....
spider = Spider("seed_input")
spider.parse(client)
spiders.py
import pickle
from person import Person
class Spider:
def __init__(self, filename):
self.person_set = Set()
self.file_to_seed(filename)
for seed_url in self.seed_list:
self.seed_to_parse_queue(seed_url)
def parse(self, client):
if os.path.exists('tmp.person_set'):
print "Program wasnt ended properly, continuing from where it left"
self.emergency_read()
... starts parsing
def emergency_write(self):
if os.path.exists('tmp.person_set'):
self.delete_emergency_files()
with open('tmp.person_set', 'wb') as f:
pickle.dump(self.person_set, f)
with open('tmp.parse_queue', 'wb') as f:
pickle.dump(self.parse_queue, f)
def emergency_read(self):
with open('tmp.person_set', 'rb') as f:
self.person_set = pickle.load(f)
with open('tmp.parse_queue', 'rb') as f:
self.parse_queue = pickle.load(f)
person.py
class Person:
def __init__(self, name):
self.name = name
self.friend_set = Set()
self.profile_url = ""
self.id = 0
self.color = "Grey"
self.parent = None
self.depth = 0
def add_friend(self, friend):
self.friend_set.add(friend)
def __repr__(self):
return "Person(%s, %s)" % (self.profile_url, self.name)
def __eq__(self, other):
if isinstance(other, Person):
return ((self.profile_url == other.profile_url) and (self.name == other.name))
else:
return False
def __ne__(self, other):
return (not self.__eq__(other))
def __hash__(self):
return hash(self.__repr__())
堆栈跟踪
python main.py
Program wasnt ended properly, continuing from where it left
Traceback (most recent call last):
File "main.py", line 47, in <module>
main()
File "main.py", line 34, in main
spider.parse(client)
File "/home/ynscn/py-workspace/lll/spiders.py", line 39, in parse
self.emergency_read()
File "/home/ynscn/py-workspace/lll/spiders.py", line 262, in emergency_read
self.person_set = pickle.load(f)
File "/usr/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/usr/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
File "/usr/lib/python2.7/pickle.py", line 1198, in load_setitem
dict[key] = value
File "/home/ynscn/py-workspace/lll/person.py", line 30, in __hash__
return hash(self.__repr__())
File "/home/ynscn/py-workspace/lll/person.py", line 18, in __repr__
return "Person(%s, %s)" % (self.profile_url, self.name)
AttributeError: Person instance has no attribute 'profile_url'
Pickle 以不确定的顺序加载 class 实例的组件。此错误发生在加载期间但在反序列化 Person.profile_url
属性之前。请注意,它在 load_setitem
期间失败,这意味着它可能正在尝试加载 friend_set
属性,这是一个集合。
您的自定义 __repr__()
依赖于 class 属性,然后您的自定义 __hash__()
(pickle
需要)依赖于 __repr__()
。
我的建议是使用 Python 的默认 __hash__
方法。那行得通吗?
如果您使用 dill
而不是 pickle
,您的代码可能会按原样序列化 。 dill
可以 pickle class 对象、实例、方法和属性……以及 python 中的大部分内容。 dill
还可以存储 classes 和 class 实例的动态修改状态。正如@nofinator 指出的那样,我同意这似乎是一个 pickle load
错误。但是,dill
可能会绕过它。
可能更好的方法是,如果您想强制加载和卸载顺序,您可以尝试添加 __getstate__
和 __setstate__
方法。
我正在尝试抓取网站。在这个网站中,我将抓取的人存储在 person_set 中,将抓取下一个人的队列存储在 parse_queue 中。在每人爬行开始的时候,我需要把这两个数据结构写到一个文件中,以防爬行因为异常或者网络不好而中断,以便后面继续。
我有三个 python 文件。一个主文件、一个蜘蛛和一个人模型。 Main实例化spider,spider开始解析,必要时调用write和read。 person 文件有 class Person,它是存储人物数据的模型。
我在读取我写入的数据时遇到问题。我检查了很多关于这个错误的问题,它似乎是一个导入问题。但是即使我将 Person class 导入到 main 和 spiders 中,它仍然给我错误。似乎 emergency_read 方法不受我的顶级导入的影响。
main.py
from spiders import Spider
from person import Person
import pickle
def main():
....
spider = Spider("seed_input")
spider.parse(client)
spiders.py
import pickle
from person import Person
class Spider:
def __init__(self, filename):
self.person_set = Set()
self.file_to_seed(filename)
for seed_url in self.seed_list:
self.seed_to_parse_queue(seed_url)
def parse(self, client):
if os.path.exists('tmp.person_set'):
print "Program wasnt ended properly, continuing from where it left"
self.emergency_read()
... starts parsing
def emergency_write(self):
if os.path.exists('tmp.person_set'):
self.delete_emergency_files()
with open('tmp.person_set', 'wb') as f:
pickle.dump(self.person_set, f)
with open('tmp.parse_queue', 'wb') as f:
pickle.dump(self.parse_queue, f)
def emergency_read(self):
with open('tmp.person_set', 'rb') as f:
self.person_set = pickle.load(f)
with open('tmp.parse_queue', 'rb') as f:
self.parse_queue = pickle.load(f)
person.py
class Person:
def __init__(self, name):
self.name = name
self.friend_set = Set()
self.profile_url = ""
self.id = 0
self.color = "Grey"
self.parent = None
self.depth = 0
def add_friend(self, friend):
self.friend_set.add(friend)
def __repr__(self):
return "Person(%s, %s)" % (self.profile_url, self.name)
def __eq__(self, other):
if isinstance(other, Person):
return ((self.profile_url == other.profile_url) and (self.name == other.name))
else:
return False
def __ne__(self, other):
return (not self.__eq__(other))
def __hash__(self):
return hash(self.__repr__())
堆栈跟踪
python main.py
Program wasnt ended properly, continuing from where it left
Traceback (most recent call last):
File "main.py", line 47, in <module>
main()
File "main.py", line 34, in main
spider.parse(client)
File "/home/ynscn/py-workspace/lll/spiders.py", line 39, in parse
self.emergency_read()
File "/home/ynscn/py-workspace/lll/spiders.py", line 262, in emergency_read
self.person_set = pickle.load(f)
File "/usr/lib/python2.7/pickle.py", line 1378, in load
return Unpickler(file).load()
File "/usr/lib/python2.7/pickle.py", line 858, in load
dispatch[key](self)
File "/usr/lib/python2.7/pickle.py", line 1198, in load_setitem
dict[key] = value
File "/home/ynscn/py-workspace/lll/person.py", line 30, in __hash__
return hash(self.__repr__())
File "/home/ynscn/py-workspace/lll/person.py", line 18, in __repr__
return "Person(%s, %s)" % (self.profile_url, self.name)
AttributeError: Person instance has no attribute 'profile_url'
Pickle 以不确定的顺序加载 class 实例的组件。此错误发生在加载期间但在反序列化 Person.profile_url
属性之前。请注意,它在 load_setitem
期间失败,这意味着它可能正在尝试加载 friend_set
属性,这是一个集合。
您的自定义 __repr__()
依赖于 class 属性,然后您的自定义 __hash__()
(pickle
需要)依赖于 __repr__()
。
我的建议是使用 Python 的默认 __hash__
方法。那行得通吗?
如果您使用 dill
而不是 pickle
,您的代码可能会按原样序列化 。 dill
可以 pickle class 对象、实例、方法和属性……以及 python 中的大部分内容。 dill
还可以存储 classes 和 class 实例的动态修改状态。正如@nofinator 指出的那样,我同意这似乎是一个 pickle load
错误。但是,dill
可能会绕过它。
可能更好的方法是,如果您想强制加载和卸载顺序,您可以尝试添加 __getstate__
和 __setstate__
方法。