蟒蛇泡菜 |基维 |将小部件结果保存在"TypeError: no default __reduce__ due to non-trivial __cinit__"



我想保存小部件的状态,如布局,按钮等,并发现pickle被推荐用于此。然而,错误是"TypeError: no defaultreduce由于非琐屑cinit";我什么也解释不了,我在网上也找不到解决办法。

我不介意其他解决方案来保存,但我尝试了json和存储模块,也不能使它工作。

我能做什么?

感谢阅读

from kivy.properties import ObjectProperty, StringProperty, NumericProperty, BoundedNumericProperty, ListProperty, BooleanProperty
from kivy.clock import Clock
from kivy.core.window import Window
from kivy.graphics import Rectangle, Color
from kivy.core.text import LabelBase
from kivy.uix.label import Label
from kivy.uix.image import Image
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.pagelayout import PageLayout
from kivy.uix.gridlayout import GridLayout
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.textinput import TextInput
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.button import Button
from kivy.uix.widget import Widget
from kivy.app import App
import numpy as np
import random
from random import randrange
from kivy.storage.jsonstore import JsonStore
import pickle
import json
class SaveButton(Button):
def __init__(self, **kwargs):
super(SaveButton, self).__init__(**kwargs)
self.background_color = (20/255, 20/255, 20/255, 1)
self.size_hint = 0.1, 0.05
self.text = "Save game"
self.pos_hint = {'center_x': .5, 'center_y': .05}
self.font_size = "22sp"

class TestScreen(Screen):
def __init__(self, **kwargs):
super(TestScreen, self).__init__(**kwargs)
self.testlayout = TestLayout()
self.add_widget(self.testlayout)

self.savebutton = SaveButton()
self.add_widget(self.savebutton)
self.savebutton.bind(on_release=self.save_game)

def save_game(self, *args):
saved_game = open("saved game.py", "w")
pickle.dump(self.testlayout, saved_game)

class TestLayout(FloatLayout):
def __init__(self, **kwargs):
super(TestLayout, self).__init__(**kwargs)
self.testbutton = TestButton()
self.add_widget(self.testbutton)
self.testbutton.bind(on_release=self.example_change)

def example_change(self, *args):
self.testbutton.pos_hint = {'center_x':.5, 'center_y':.8}

class TestButton(Button):
def __init__(self, **kwargs):
super(TestButton, self).__init__(**kwargs)
self.size_hint = 0.05, 0.1
self.pos_hint = {'center_x':.5, 'center_y':.5}

class Manager(ScreenManager):
def __init__(self, **kwargs):
super(Manager, self).__init__(**kwargs)
self.testscreen = TestScreen()
self.testscreen.name = "testscreen"
self.add_widget(self.testscreen)
class DemoApp(App):
def build(self):
self.manager = Manager()
return self.manager
DemoApp().run()

通常推荐使用Pickle,因为它"容易",但很多时候这实际上是一个坏主意,因为尽管您没有编写很多行代码,但实际结果并不是很好——Pickle文件很大、不透明、不安全(这可能重要,也可能无关紧要),而且不可靠,因为只有在加载环境与生成Pickle的环境足够相似时才能再次加载它们。

进一步,pickle不能序列化所有的东西,这就是你在这里遇到的问题:这个错误本质上是说kivy类做了一些pickle不能存储的事情。我不确定是否有可能使用不同的pickle协议来解决这个问题,但我建议根本不要使用pickle。

你可能想要的是写一个函数来接收你的小部件并存储所有关于它的重要细节(例如,你关心的每个属性的值),然后另一个函数接收该细节并重建一个新的小部件,并将所有属性设置为该值。这是更多的前期工作,但最终更清晰,更可靠。一旦你生成了重建小部件所需的信息(例如,作为字典),你可以用e.g. json保存它,但你不能将小部件本身保存为json,因为json只支持一系列特定的对象类型。

编辑:这并不是说pickle普遍不好,它对于例如在python多进程之间传递对象是有好处的,因为这样你就不必担心不同的python环境或缺乏安全性。

相关内容

最新更新