破解书中代码的 Pickle 模块 "Conceptual Programming with Python"
Pickle module that breaks the code from the book "Conceptual Programming with Python"
我正在使用“使用 Python 进行概念编程”一书中的示例。
代码旨在解决的问题的一些介绍:
示例:创建知识库
作为面向对象编程的第二个例子,我们将实现一个简单的猜谜游戏!但是这个游戏将能够从经验中学习,也就是说,你将能够在玩的过程中教授程序。对于这个例子,我们将创建一个动物知识库。用户会想到一种动物,而计算机将不得不通过向您询问有关该动物的(明智的)问题来弄清楚它是哪种动物;答案要么是,要么不是。如果它没有猜对动物,程序会问你什么是一个明智的问题,以便下次能够找到正确的解决方案!
例1:计算机只知道如何区分鸟或猫,看它是否有4条腿。即初始知识库只有这两种动物和一个问题。
- 你:想想猫。
- 电脑:它有4条腿吗?
- 你:是
- 计算机:你在想猫吗?
- 你:是
- 电脑:我就知道!!让我们继续玩吧!我擅长这个!
再一次,这遵循树结构!根据用户的回答是或否,计算机会提出不同的问题,或提供答案!
例2:你教电脑一道新题。
- 你:想想狗。
- 电脑:它有4条腿吗?
- 你:是
- 计算机:你在想猫吗?
- 你:没有
- 电脑:你想到的是什么动物?
- 你:狗
- 计算机:请问区分狗和猫的问题是什么?
- 你:它叫吗?
- 计算机:给一只狗,答案应该是什么?
- 你:是
现在 pickle 片段:
文件总是需要先打开;然后操作它们(例如将它们的内容加载到数据结构中),最后在它们不再使用时关闭它们。因此,我们将尝试打开一个名为 animal.kb 的文件,我们将在其中保存树。我们第一次打开文件时,它是空的,所以我们将创建我们以前的知识库。为此,我们将使用 try-except 结构。为什么?每当我们尝试打开一个不存在的文件时,这将创建一个异常 FileNotFoundError。我们可以简单地捕捉它并“手动”创建知识库。然后我们让用户玩,我们不断更新知识库kb。程序结束时,当用户不想玩了,我们将kb中包含的信息‘dump’到文件“animal.kb”。
第二次尝试打开“animal.kb”知识库后出现错误:
```
Do you want to play? y
Traceback (most recent call last):
File "...\ConceptualPython02\knowledgeBase.py", line 71, in <module>
kb = kb.play()
AttributeError: 'NoneType' object has no attribute 'play'
Process finished with exit code 1
```
那是有问题的代码:
import pickle
class Knowledge:
pass
class Question(Knowledge):
def __init__(self, text, if_yes, if_no):
self.text, self.if_yes, self.if_no = text, if_yes, if_no
def play(self):
if ask(self.text):
self.if_yes = self.if_yes.play()
else:
self.if_no = self.if_no.play()
return self
class Answer(Knowledge):
def __init__(self, text):
self.text = text
def play(self):
if ask("Were you thinking of a {} ? ".format(self.text)):
print("I knew it!")
return self
# here we got it right, # so we simply return the
# Answer node as it is.
else:
newanimal = input("What animal were\ "
"you thinking of? ")
newquestion = input("What is a question "
"to distinguish between {} and {} ?"
.format(self.text, newanimal))
# but in case we didn't know the animal
# we need to modify the node adding # the appropriate question and# what to do
# ifyes and if no
if ask("For {} , what should be the answer? ".format(newanimal)):
return Question(newquestion,
Answer(newanimal), self)
else:
return Question(newquestion,
self, Answer(newanimal))
def ask(q):
while True:
ans = input(q + " ")
if ans == "y":
return True
elif ans == "n":
return False
else:
print("Please answer y or n!")
try:
file = open("animal.kb", "rb")
kb = pickle.load(file)
file.close()
except FileNotFoundError:
kb = Question("Does it have 4 legs?", Question("Does it bark?",
Answer("dog"), Answer("cat")), Answer("bird"))
while True:
if not ask("Do you want to play?"):
break
kb = kb.play()
file = open("animal.kb", "wb")
pickle.dump(kb, file)
file.close()
当然,它也没有像应该的那样缓存关于动物的新问题。
play
应该总是 return 一个 Knowledge
实例(或继承自它)。但是当在 Question.play
中调用 ask
returns True
时,你不会 return 任何东西:
def play(self):
if ask(self.text):
self.if_yes = self.if_yes.play()
else:
self.if_no = self.if_no.play()
return self
所以改变 return self
的缩进,所以它总是被执行。
我正在使用“使用 Python 进行概念编程”一书中的示例。
代码旨在解决的问题的一些介绍:
示例:创建知识库
作为面向对象编程的第二个例子,我们将实现一个简单的猜谜游戏!但是这个游戏将能够从经验中学习,也就是说,你将能够在玩的过程中教授程序。对于这个例子,我们将创建一个动物知识库。用户会想到一种动物,而计算机将不得不通过向您询问有关该动物的(明智的)问题来弄清楚它是哪种动物;答案要么是,要么不是。如果它没有猜对动物,程序会问你什么是一个明智的问题,以便下次能够找到正确的解决方案!
例1:计算机只知道如何区分鸟或猫,看它是否有4条腿。即初始知识库只有这两种动物和一个问题。
- 你:想想猫。
- 电脑:它有4条腿吗?
- 你:是
- 计算机:你在想猫吗?
- 你:是
- 电脑:我就知道!!让我们继续玩吧!我擅长这个!
再一次,这遵循树结构!根据用户的回答是或否,计算机会提出不同的问题,或提供答案!
例2:你教电脑一道新题。
- 你:想想狗。
- 电脑:它有4条腿吗?
- 你:是
- 计算机:你在想猫吗?
- 你:没有
- 电脑:你想到的是什么动物?
- 你:狗
- 计算机:请问区分狗和猫的问题是什么?
- 你:它叫吗?
- 计算机:给一只狗,答案应该是什么?
- 你:是
现在 pickle 片段:
文件总是需要先打开;然后操作它们(例如将它们的内容加载到数据结构中),最后在它们不再使用时关闭它们。因此,我们将尝试打开一个名为 animal.kb 的文件,我们将在其中保存树。我们第一次打开文件时,它是空的,所以我们将创建我们以前的知识库。为此,我们将使用 try-except 结构。为什么?每当我们尝试打开一个不存在的文件时,这将创建一个异常 FileNotFoundError。我们可以简单地捕捉它并“手动”创建知识库。然后我们让用户玩,我们不断更新知识库kb。程序结束时,当用户不想玩了,我们将kb中包含的信息‘dump’到文件“animal.kb”。
第二次尝试打开“animal.kb”知识库后出现错误:
```
Do you want to play? y
Traceback (most recent call last):
File "...\ConceptualPython02\knowledgeBase.py", line 71, in <module>
kb = kb.play()
AttributeError: 'NoneType' object has no attribute 'play'
Process finished with exit code 1
```
那是有问题的代码:
import pickle
class Knowledge:
pass
class Question(Knowledge):
def __init__(self, text, if_yes, if_no):
self.text, self.if_yes, self.if_no = text, if_yes, if_no
def play(self):
if ask(self.text):
self.if_yes = self.if_yes.play()
else:
self.if_no = self.if_no.play()
return self
class Answer(Knowledge):
def __init__(self, text):
self.text = text
def play(self):
if ask("Were you thinking of a {} ? ".format(self.text)):
print("I knew it!")
return self
# here we got it right, # so we simply return the
# Answer node as it is.
else:
newanimal = input("What animal were\ "
"you thinking of? ")
newquestion = input("What is a question "
"to distinguish between {} and {} ?"
.format(self.text, newanimal))
# but in case we didn't know the animal
# we need to modify the node adding # the appropriate question and# what to do
# ifyes and if no
if ask("For {} , what should be the answer? ".format(newanimal)):
return Question(newquestion,
Answer(newanimal), self)
else:
return Question(newquestion,
self, Answer(newanimal))
def ask(q):
while True:
ans = input(q + " ")
if ans == "y":
return True
elif ans == "n":
return False
else:
print("Please answer y or n!")
try:
file = open("animal.kb", "rb")
kb = pickle.load(file)
file.close()
except FileNotFoundError:
kb = Question("Does it have 4 legs?", Question("Does it bark?",
Answer("dog"), Answer("cat")), Answer("bird"))
while True:
if not ask("Do you want to play?"):
break
kb = kb.play()
file = open("animal.kb", "wb")
pickle.dump(kb, file)
file.close()
当然,它也没有像应该的那样缓存关于动物的新问题。
play
应该总是 return 一个 Knowledge
实例(或继承自它)。但是当在 Question.play
中调用 ask
returns True
时,你不会 return 任何东西:
def play(self):
if ask(self.text):
self.if_yes = self.if_yes.play()
else:
self.if_no = self.if_no.play()
return self
所以改变 return self
的缩进,所以它总是被执行。