我正在尝试将类的实例保存到Python 3.7中的字符串中。
我正在尝试这样做是因为我已经开始制作一个基于文本的游戏,该游戏具有世界坐标系和类实例的字典(我遵循了本教程:https://letstalkdata.com/2014/08/how-to-write-a-text-adventure-in-python/),我想要添加一个保存选项。如果您只是腌制世界词典,它会说房间在RAM中的什么位置,这不是很有帮助。但是后来我在某个地方读到了repr()
和exec()
,我现在正试图用它来保存和加载测试类的实例。但是,当我尝试打印新创建的类实例时,它会给我一个RecursionError: maximum recursion depth exceeded
。
import traceback
def change_char(s, p, r):
l = list(s)
l[p] = r
return "".join(l)
class Class:
def __init__(self, i1, i2, *i3):
(filename,line_number,function_name,text)=traceback.extract_stack()[-2]
self.name = text[:text.find('=')].strip()
self.i1 = i1
self.i2 = i2
self.i3 = []
for iv in i3:
self.i3.append(iv)
def l(self, l):
s = ''
i = 1
for e in l:
if i < len(l):
s = s + repr(e) + ", "
else:
s = s + repr(e)
i += 1
return s
@property
def print_vals(self):
print('i1 : {1}\ni2 : {2}\ni3 : {3}'.format(self.i1, self.i2, self.l(self.i3)))
def __repr__(self):
return '{0} = Class({1}, {2}, {3})'.format(self.name, repr(self.i1), repr(self.i2), self.l(self.i3))
@property
def save(self):
return repr(self)
def Classload(st):
name = st[:st.find('=')].strip()
exec('global '+name+'\n'+st)
exec('global '+name+'\n'+name+'.name = '+name)
c = Class(1, "str", "Hello", 'world!')
print(repr(c))
i = c.save
i = change_char(i, 0, 'i')
print(i)
Classload(i)
print(c)
print(i)
print(repr(c))
print(repr(i))
我希望输出为:
c = Class(1, 'str', 'Hello', 'world!')
i = Class(1, 'str', 'Hello', 'world!')
c = Class(1, 'str', 'Hello', 'world!')
i = Class(1, 'str', 'Hello', 'world!')
c = Class(1, 'str', 'Hello', 'world!')
i = Class(1, 'str', 'Hello', 'world!')
但是我得到了
c = Class(1, 'str', 'Hello', 'world!')
i = Class(1, 'str', 'Hello', 'world!')
c = Class(1, 'str', 'Hello', 'world!')
Traceback (most recent call last):
File "C:\Users\HP\Desktop\test.py", line 107, in <module>
print(i)
File "C:\Users\HP\Desktop\test.py", line 63, in __repr__
return '{0} = Class({1}, {2}, {3})'.format(self.name, repr(self.i1), repr(self.i2), self.l(self.i3))
File "C:\Users\HP\Desktop\test.py", line 63, in __repr__
return '{0} = Class({1}, {2}, {3})'.format(self.name, repr(self.i1), repr(self.i2), self.l(self.i3))
File "C:\Users\HP\Desktop\test.py", line 63, in __repr__
return '{0} = Class({1}, {2}, {3})'.format(self.name, repr(self.i1), repr(self.i2), self.l(self.i3))
[Previous line repeated 245 more times]
RecursionError: maximum recursion depth exceeded
我该如何解决?
答案 0 :(得分:1)
对象的名称是对象本身。如果您打印执行的内容,则它看起来像这样:
global i
i = Class(1, 'str', 'Hello', 'world!')
global i
i.name = i
在i上调用repr
时,它将尝试将i.name
表示为字符串,但要转换i.name
(即i
)以转换它调用的ta字符串repr
。 repr
然后将尝试将i.name.name
(即i.name
,即i
表示为字符串,...直到超过递归深度为止。
在类加载中,您宁愿想要
i.name = 'i'
一般来说,使用repr和exec作为保存系统不是一个好主意。这是非常挑剔的,基本上可以归结为repr不被设计为机器可读(但人类可读),而exec几乎从来不是任何事物的正确选择。相反,您可以使用de / serializer(即将python对象转换为字节并将字节转换为python对象的代码),例如pickle或json或protobuf或xml。我真的不理解您对泡菜的反对,因为它基本上是为您的用例设计的。
答案 1 :(得分:0)
关于您对泡菜的评论-在文档(https://docs.python.org/3.7/library/pickle.html#comparison-with-marshal)中说:
pickle模块跟踪已序列化的对象,因此以后对同一对象的引用将不再被序列化。
大概是为什么有内存引用。只需执行以下操作就很容易了:
if __name__ == '__main__':
import pickle
initial = Class(1, 'hello', 'world', '!')
dumped = pickle.dumps(initial)
returned = pickle.loads(dumped)
print(f'initial: {initial}')
print(f'returned: {returned}')
print(f'i1: {returned.i1}, i2: {returned.i2}, i3: {returned.i3}')
# initial: Class(1, 'hello', 'world', '!')
# returned: Class(1, 'hello', 'world', '!')
# i1: 1, i2: hello, i3: ['world', '!']
注意,尽管如此,我也删除了代码中的类名,这就是为什么打印输出与众不同的原因。