【问题标题】:Saving dict with nested class instances in Python 2.7在 Python 2.7 中保存带有嵌套类实例的字典
【发布时间】:2013-04-12 03:49:23
【问题描述】:

我试图让这件事尽可能简单。基本上我希望将数据保存到一个文件中,然后检索它,以便 questor.py 工作并且可以“记住”它曾经在你的机器上教过的所有内容。原始代码可在网络上http://www.strout.net/info/coding/python/questor.py 获得 如果我没看错代码,你最终会得到一个类似于 {key:{key:{key:class instance},class instance},class instance} 的对象。 (粗略估计)

请忽略未捕获的方法 Save,我正在研究如何在不丢失任何嵌入实例的情况下腌制字典。

以下是我尝试通过pickler 保存字典的尝试。一些代码未完成,但你应该能够了解我想要做什么。到目前为止,我所能做的就是检索最后一个问题/答案集。我的泡菜没有保存嵌入的实例,或者当我保存泡菜时它们实际上并不存在。我已经尽可能多地遵循意大利面条线,但似乎无法弄清楚如何设置一种在不丢失任何内容的情况下保存到文件的方法。 此外,我的文件不必是 .txt,最初我打算将 .data 用于泡菜。

# questor.py 

# define some constants for future use
kQuestion = 'question'
kGuess = 'guess'
questfile = 'questfile.txt'

## Added
import cPickle as p
# create a file for questor
def questor_file():
    try:
        questor = open(questfile,'rb')
        try:
            q = p.Unpickler(questor)
            quest = q.load()
            questor.close()
            return quest
        except:
            print 'P.load failed'
    except:
        print 'File did not open'
        questor = open('questfile.data', 'wb')
        questor.close()
    return Qnode('python')

# define a function for asking yes/no questions
def yesno(prompt):
    ans = raw_input(prompt)
    return (ans[0]=='y' or ans[0]=='Y')

# define a node in the question tree (either question or guess)
class Qnode:

    # initialization method
    def __init__(self,guess):
        self.nodetype = kGuess
        self.desc = guess

    ##Added
    ## Not sure where I found this, but was going to attempt to use this as a retreival method
    ## haven't gotten this to work yet
    def Load(self):
        f = open(self.questfile,'rb')
        tmp_dict = cPickle.load(f)
        f.close()    
        self.__dict__.update(tmp_dict) 

    ##Added
    # was going to use this as a save method, and call it each time I added a new question/answer
    def Save(self,node):
        f = open(self.questfile,'wb')
        quest = p.pickler(f)


    # get the question to ask 
    def query(self):
        if (self.nodetype == kQuestion):
            return self.desc + " "
        elif (self.nodetype == kGuess):
            return "Is it a " + self.desc + "? "
        else:
            return "Error: invalid node type!"

    # return new node, given a boolean response
    def nextnode(self,answer):
        return self.nodes[answer]

    # turn a guess node into a question node and add new item
    # give a question, the new item, and the answer for that item
    def makeQuest( self, question, newitem, newanswer ):

        # create new nodes for the new answer and old answer
        newAnsNode = (Qnode(newitem))
        oldAnsNode = (Qnode(self.desc))

        # turn this node into a question node
        self.nodetype = kQuestion
        self.desc = question

        # assign the yes and no nodes appropriately
        self.nodes = {newanswer:newAnsNode, not newanswer:oldAnsNode}
        self.save(self.nodes)


def traverse(fromNode):
    # ask the question
    yes = yesno( fromNode.query() )

    # if this is a guess node, then did we get it right?
    if (fromNode.nodetype == kGuess):
        if (yes):
            print "I'm a genius!!!"
            return
        # if we didn't get it right, return the node
        return fromNode

    # if it's a question node, then ask another question
    return traverse( fromNode.nextnode(yes) )

def run():
    # start with a single guess node
    # This was supposed to assign the data from the file
    topNode = questor_file()


    done = 0
    while not done:
        # ask questions till we get to the end
        result = traverse( topNode )


        # if result is a node, we need to add a question
        if (result):
            item = raw_input("OK, what were you thinking of? ")
            print "Enter a question that distinguishes a",
            print item, "from a", result.desc + ":"
            q = raw_input()
            ans = yesno("What is the answer for " + item + "? ")
            result.makeQuest( q, item, ans )
            print "Got it."

        # repeat until done
        print
        done = not yesno("Do another? ")
    # Added
    # give me the dictionary    
    return result

# immediate-mode commands, for drag-and-drop or execfile() execution
if __name__ == '__main__':
    print "Let's play a game."
    print 'Think of something, just one thing.'
    print 'It can be anything, and I will try to guess what it is.'
    raw_input('Press Enter when ready.')
    print
    questdata = run()
    print
    # Added
    # Save the dictionary
    questor = open(questfile,'wb')
    q = p.Pickler(questor)
    q.dump(questdata)
    questor.close()
    raw_input("press Return>")
else:
    print "Module questor imported."
    print "To run, type: questor.run()"
    print "To reload after changes to the source, type: reload(questor)"

# end of questor.py

【问题讨论】:

  • 我猜你想让你的 QClass 可以腌制?看到这个帖子stackoverflow.com/questions/4109848/…
  • 对不起,我把原来的代码去掉,反正网上都有,我只是给个参考
  • @Joran Beasley 触及了我需要的东西,但我可以腌制字典并保存它,甚至从文件中检索它,我的问题是我丢失了所有嵌套的类实例。单独我可以腌制这些类,问题是我不确定我是否从一开始就正确理解了代码。我对 makeQuest 的假设是否正确?
  • 看起来像...但Save 函数实际上看起来不像在保存...您也在调用save(nodes),但您的方法签名看起来像Save(node_list) ...如果这是为了某种任务我不确定你会从这段代码中学到什么......
  • @JoranBeasley 不要担心未完成的代码,我将删除它或稍后完成它

标签: python pickle class-instance-variables


【解决方案1】:

想到的一种方法是创建所有节点的列表并保存...它们应该自己保留内部指针。

在文件顶部声明一个节点列表(并使用pickle...只是因为我更熟悉它)

import pickle
kQuestion = 'question'
kGuess = 'guess'
questfile = 'questfile.txt'
nodes = []
....

将您的加载方法更改为类似

def questor_file():
    global nodes
    try:
        questor = open(questfile,'rb')
        try:
            nodes= pickle.load(questor)
            quest = nodes[0]
            questor.close()
            return quest
        except:
            print 'P.load failed'
            nodes = []

    except:
        print 'File did not open'
        nodes = []
    return Qnode('python')

更改您的类构造函数,以便将每个节点添加到节点

class Qnode:
    # initialization method
    def __init__(self,guess):
        self.nodetype = kGuess
        self.desc = guess
        nodes.append(self)

在它显示 #added save dictionary 的末尾,保存您的节点列表

questor = open(questfile,'wb')
q = pickle.dump(nodes,questor)

请确保在出现提示时键入 no 退出程序...

您也可以将其保存到数据库或其他任何地方,但您仍然必须存储每个节点,并且可能会更复杂......我认为这种方法应该真的很好,(尽管可能有更自然的方法来保存树结构)...

【讨论】:

  • 啊,谢谢,我什至没有想到这一点,而且我不知道类 init 可以修改全局对象,这很有帮助。现在要弄清楚如何让程序迭代列表或从列表中重建字典,以便下次运行它时,它会“记住”所有旧内容。
  • 追加不会仅在实例初始化时将实例附加到列表中,还是允许它在修改实例数据时更改实例数据?换句话说,在实例初始化后更改字典时,追加是否会在每个实例调用时添加新字典?
  • 试试看 ;) ...它是一个可变对象,所以列表应该更新
猜你喜欢
  • 2020-10-22
  • 1970-01-01
  • 2015-09-30
  • 1970-01-01
  • 2019-06-13
  • 1970-01-01
  • 2015-04-11
  • 1970-01-01
  • 2017-03-09
相关资源
最近更新 更多