您正在查看: Python 分类下的文章

习题 51: 评审你的游戏

习题 51: 评审你的游戏

你在这个“黑手党外星人奴隶船”游戏上面花了不少功夫了,你设计了一个很好的故事主线,布置了各个房间,创建了一个不错的游戏引擎,而且最终让游戏运行起来了。现在你的游戏将被一个真正的用户审核过,而且你要记录下他们发现的错误。这个过程叫做“可用性测试(usability test)”,它可以帮你得到很好的反馈,而且为你找到你预料不到的新 bug。

当你写游戏的时候,你可能只测试了你知道的东西。问题是别人其实不知道你游戏的设计结构,所以他们会用各种你没想到的奇怪方法使用你的游戏。要测试到这些奇怪方法,唯一的方法就是把你的游戏交给别人去玩,让他们随意折腾这个游戏。

去找一个人吧,亲戚朋友是最好的了,也许你还可以找别的使用这本书学习的人,分享一些学习的经验,甚至你们可以把这搞成一个竞赛,看谁写的游戏更好。总之,你要找人来,让他们亲自玩你的游戏。

如何研究用户行为

研究用户很容易。把游戏给他们,然后观察两样东西。

  • 观察他们的电脑屏幕。
  • 观察他们的表情。
  • 你可以坐在他们侧面,这样你两样就都能看到了。你可以通过他们的表情观察到他们对你的游戏的反应。

    让他们玩你的游戏,并且对你的游戏直接进行评论。告诉他们让他们一边玩一边评论这个游戏,这样他们会告诉你各种各样的东西。

    在他们边玩边说的时候,你在纸上记录下他们讲的内容,千万不要对这些内容进行评判,或者跟他们争论什么。记下他们说的就可以了。你需要的是他们对于游戏诚实的反馈,如果你把这当做是对你的评价而且让这件事情情绪化,那你就不会得到真正的反馈了。

    让他们尝试游戏中困难的地方,然后帮他们过关。你应该把难度太大、功能有问题、容易迷失等所有的有问题的部分记录下来。

    最后,你要感谢他们帮你评审你的游戏,和他们一起回顾你记录下来的内容。如果你这样做的话,下一次你找他们帮忙评审,他们也会很乐意的,而且这也是基本的礼貌。

    修改你的游戏

    有了一份问题点,你需要再做一份列表,里边包含的是你要修改的内容。花一个星期修改你的游戏,然后叫你的朋友再为你评审一遍。

    他们喜不喜欢你的游戏并不重要,重要的是你面对了一个需求描述模糊的项目,完成了这个项目,得到了用户反馈,而且针对用户反馈修改了你的游戏。你的游戏程序可能很差,但至少你完整地写出来了。

    你要认真对待本节的内容,虽然本节没有代码,但这也许是你学到的最重要的一课。它让你明白软件是为别人写的,所以写软件很重要的一点就是在意别人的观点。

    Project Versions

    Table Of Contents

    • 习题 51: 评审你的游戏
      • 如何研究用户行为
      • 修改你的游戏

    Previous topic

    习题 50: 你的第一项工作任务

    Next topic

    习题 52: 把你会的教给别人

    This Page

    • Show Source

    Quick search

    Enter search terms or a module, class or function name.

    习题 52: 把你会的教给别人

    习题 52: 把你会的教给别人

    通过阅读本书学习写软件的过程让你学会了很多人没有学过的东西。然而,你也许还不知道自己会的东西究竟有多少。为了让你对自己的知识量有个概念,让你明白自己究竟会了哪些东西,我会给你一个比较艰巨的任务:

    把习题 1 到 5 的内容教给另一个人。

    没错,你需要当一天老师,教另一个没有写过程序的人开始接触编程。至于后果嘛,要么他们会喜欢上编程,等你教完后还会继续学习,要么觉得很没趣,学完就丢一边忘记了。谁知道呢。

    这节课的目的是让你学会清楚地向别人解释一些概念。这样的过程也可以让你对自己学到的东西有更清楚和牢固的理解。

    我以前有一个钢琴老师,他曾今在很多爵士乐队做过专职演出,弹奏过各种复杂的音乐,但他告诉我,直到他开始 教授 爵士乐的时候,他才真正明白了他做的事情。

    教学的过程会强迫你让你明白你所作的事情。

    加分习题

    • 找一个当地的“python 小组”并参加他们的聚会。如果你的所在地没有 python 小组,试着和你的朋友一起创建一个出来。

    Project Versions

    Table Of Contents

    • 习题 52: 把你会的教给别人
      • 加分习题

    Previous topic

    习题 51: 评审你的游戏

    Next topic

    下一步

    This Page

    • Show Source

    Quick search

    Enter search terms or a module, class or function name.

    习题 45: 对象、类、以及从属关系

    习题 45: 对象、类、以及从属关系

    有一个重要的概念你需要弄明白,那就是“类(class)”和“对象(object)”的区别。问题在于,class 和 object 并没有真正的不同。它们其实是同样的东西,只是在不同的时间名字不同罢了。我用禅语来解释一下吧:

    鱼和泥鳅有什么区别?

    这个问题有没有让你有点晕呢?说真的,坐下来想一分钟。我的意思是说,鱼和泥鳅是不一样,不过它们其实也是一样的是不是?泥鳅是鱼的一种,所以说没什么不同,不过泥鳅又有些特别,它和别的种类的鱼的确不一样,比如泥鳅和黄鳝就不一样。所以泥鳅和鱼既相同又不同。怪了。

    这个问题让人晕的原因是大部分人不会这样去思考问题,其实每个人都懂这一点,你无须去思考鱼和泥鳅的区别,因为你知道它们之间的关系。你知道泥鳅是鱼的一种,而且鱼还有别的种类,根本就没必要去思考这类问题。

    让我们更进一步,假设你有一只水桶,里边有三条泥鳅。假设你的好人卡多到没地方用,于是你给它们分别取名叫小方,小斌,小星。现在想想这个问题:

    小方和泥鳅有什么区别?

    这个问题一样的奇怪,但比起鱼和泥鳅的问题来还好点。你知道小方是一条泥鳅,所以他并没什么不同,他只是泥鳅的一个“实例(instance)”。小斌和小星一样也是泥鳅的实例。我的意思是说,它们是由泥鳅创建出来的,而且代表着和泥鳅一样的属性。

    所以我们的思维方式是(你可能会有点不习惯):鱼是一个“类(class)”,泥鳅是一个“类(class)”,而小方是一个“对象(object)”。仔细想想,然后我再一点一点慢慢解释给你。

    鱼是一个“类”,表示它不是一个真正的东西,而是一个用来描述具有同类属性的实例的概括性词汇。 你有鳍?你有鳔?你住在水里?好吧那你就是一条鱼。

    后来河蟹养殖专家路过,看到你的水桶,于是告诉你:“小伙子,你这些鱼是泥鳅。” 专家一出,真相即现。并且专家还定义了一个新的叫做“泥鳅”的“类”,而这个“类”又有它特定的属性。细长条?有胡须?爱钻泥巴?吃起来味道还可以?那你就是一条泥鳅。

    最后家庭煮父过来了,他跟河蟹专家说:“非也非也,你看到的是泥鳅,我看到的是小方,而且我要把小方和剁椒配一起做一道小菜。”于是你就有了一只叫做小方的泥鳅的“实例(instance)”(泥鳅也是鱼的一个“实例”),并且你使用了它(把它塞到你的胃里了),这样它就是一个“对象(object)”。

    这会你应该了解了:小方是泥鳅的成员,而泥鳅又是鱼的成员。这里的关系式:对象属于某个类,而某个类又属于另一个类。

    写成代码是什么样子

    这个概念有点绕人,不过实话说,你只要在创建和使用 class 的时候操心一下就可以了。我来给你两个区分 Class 和 Object 的小技巧。

    首先针对类和对象,你需要学会两个说法,“is-a(是啥)”和“has-a(有啥)”。“是啥”要用在谈论“两者以类的关系互相关联”的时候,而“有啥”要用在“两者无共同点,仅是互为参照”的时候。

    接下来,通读这段代码,将每一个注解为 ##?? 的位置标明他是“is-a”还是“has-a”的关系,并讲明白这个关系是什么。在代码的开始我还举了几个例子,所以你只要写剩下的就可以了。

    记住,“是啥”指的是鱼和泥鳅的关系,而“有啥”指的是泥鳅和鳃的关系。

    (译注:为了解释方便,译文使用了中文鱼名。原文使用的是“三文鱼(salmon)”和“大比目鱼(halibut)”,名字也是英文常用人名。)

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    ## Animal is-a object (yes, sort of confusing) look at the extra credit
    class Animal(object):
     pass
    

    ??

    class Dog(Animal):

    def init(self, name):

    ??

    self.name = name

    ??

    class Cat(Animal):

    def init(self, name):

    ??

    self.name = name

    ??

    class Person(object):

    def init(self, name):

    ??

    self.name = name

    Person has-a pet of some kind

    self.pet = None

    ??

    class Employee(Person):

    def init(self, name, salary):

    ?? hmm what is this strange magic?

    super(Employee, self).init(name)

    ??

    self.salary = salary

    ??

    class Fish(object):
    pass

    ??

    class Salmon(Fish):
    pass

    ??

    class Halibut(Fish):
    pass

    rover is-a Dog

    rover = Dog("Rover")

    ??

    satan = Cat("Satan")

    ??

    mary = Person("Mary")

    ??

    mary.pet = satan

    ??

    frank = Employee("Frank", 120000)

    ??

    frank.pet = rover

    ??

    flipper = Fish()

    ??

    crouse = Salmon()

    ??

    harry = Halibut()

    关于 class Name(object)

    记得我曾经强迫让你使用 class Name(object) 却没告诉你为什么吧,现在你已经知道了“类”和“对象”的区别,我就可以告诉你原因了。如果我早告诉你的话,你可能会晕掉,也学不会这门技术了。

    真正的原因是在 python 早期,它对于 class 的定义在很多方面都是严重有问题的。当他们承认这一点的时候已经太迟了,所以逼不得已,他们需要支持这种有问题的 class。为了解决已有的问题,他们需要引入一种“新类”,这样的话“旧类”还能继续使用,而你也有一个新的正确的类可以使用了。

    这就用到了“类即是对象”的概念。他们决定用小写的“object”这个词作为一个类,让你在创建新类时从它继承下来。有点晕了吧?一个类从另一个类继承,而后者虽然是个类,但名字却叫“object”……不过在定义类的时候,别忘记要从 object 继承就好了。

    的确如此。一个词的不同就让这个概念变得更难理解,让我不得不现在才讲给你。现在你可以试着去理解“一个是对象的类”这个概念了,如果你感兴趣的话。

    不过我还是建议你别去理解了,干脆完全忘记旧格式和新格式类的区别吧,就假设 python 的 class 永远都要求你加上 (object) 好了,你的脑力要留着思考更重要的问题。

    加分习题

  • 研究一下为什么 Python 添加了这个奇怪的叫做 object 的 class,它究竟有什么含义呢?
  • 有没有办法把 Class 当作 Object 使用呢?
  • 在习题中为 animals、fish、还有 people 添加一些函数,让它们做一些事情。看看当函数在 Animal 这样的“基类(base class)”里和在 Dog 里有什么区别。
  • 找些别人的代码,理清里边的“是啥”和“有啥”的关系。
  • 使用列表和字典创建一些新的一对应多的“has-many”的关系。
  • 你认为会有一种“has-many”的关系吗?阅读一下关于“多重继承(multiple inheritance)”的资料,然后尽量避免这种用法。
  • Project Versions

    Table Of Contents

    • 习题 45: 对象、类、以及从属关系
      • 写成代码是什么样子
        • 关于 class Name(object)
        • 加分习题

    Previous topic

    习题 44: 给你的游戏打分

    Next topic

    习题 46: 一个项目骨架

    This Page

    • Show Source

    Quick search

    Enter search terms or a module, class or function name.

    习题 46: 一个项目骨架

    习题 46: 一个项目骨架

    这里你将学会如何建立一个项目“骨架”目录。这个骨架目录具备让项目跑起来的所有基本内容。它里边会包含你的项目文件布局、自动化测试代码,模组,以及安装脚本。当你建立一个新项目的时候,只要把这个目录复制过去,改改目录的名字,再编辑里边的文件就行了。

    骨架内容: linux/OSX

    首先使用下述命令创建你的骨架目录:

    ~ $ mkdir -p projects
    ~ $ cd projects/
    ~/projects $ mkdir skeleton
    ~/projects $ cd skeleton
    ~/projects/skeleton $ mkdir bin NAME tests docs
    

    我使用了一个叫 projects 的目录,用来存放我自己的各个项目。然后我在里边建立了一个叫做 skeleton 的文件夹,这就是我们新项目的基础目录。其中叫做NAME 的文件夹是你的项目的主文件夹,你可以将它任意取名。

    接下来我们要配置一些初始文件:

    ~/projects/skeleton $ touch NAME/__init__.py
    ~/projects/skeleton $ touch tests/__init__.py
    

    以上命令为你创建了空的模组目录,以供你后面为其添加代码。然后我们需要建立一个 setup.py 文件,这个文件在安装项目的时候我们会用到它:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    try:
     from setuptools import setup
    except ImportError:
     from distutils.core import setup
    

    config = {
    'description': 'My Project',
    'author': 'My Name',
    'url': 'URL to get it at.',
    'download_url': 'Where to download it.',
    'author_email': 'My email.',
    'version': '0.1',
    'install_requires': ['nose'],
    'packages': ['NAME'],
    'scripts': [],
    'name': 'projectname'
    }

    setup(**config)

    编辑这个文件,把自己的联系方式写进去,然后放到那里就行了。

    最后你需要一个简单的测试专用的骨架文件叫 tests/NAME_tests.py:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    from nose.tools import *
    import NAME
    

    def setup():
    print "SETUP!"

    def teardown():
    print "TEAR DOWN!"

    def test_basic():
    print "I RAN!"

    python 软件包的安装

    你需要预先安装一些软件包,不过问题就来了。我的本意是让这本书越清晰越干净越好,不过安装软件的方法是在是太多了,如果我要一步一步写下来,那 10 页都写不完,而且告诉你吧,我本来就是个懒人。

    所以我不会提供详细的安装步骤了,我只会告诉你需要安装哪些东西,然后让你自己搞定。这对你也有好处,因为你将打开一个全新的世界,里边充满了其他人发布的 python 软件。

    接下来你需要安装下面的软件包:

  • pip – http://pypi.python.org/pypi/pip
  • distribute – http://pypi.python.org/pypi/distribute
  • nose – http://pypi.python.org/pypi/nose/
  • virtualenv – http://pypi.python.org/pypi/virtualenv
  • 不要只是手动下载并且安装这些软件包,你应该看一下别人的建议,尤其看看针对你的操作系统别人是怎样建议你安装和使用的。同样的软件包在不一样的操作系统上面的安装方式是不一样的,不一样版本的 linux 和 OSX 会有不同,而 Windows 更是不同。

    我要预先警告你,这个过程会是相当无趣。在业内我们将这种事情叫做 “yak shaving(剃牦牛)”。它指的是在你做一件有意义的事情之前的一些准备工作,而这些准备工作又是及其无聊冗繁的。你要做一个很酷的 Python 项目,但是创建骨架目录需要你安装一些软件包,而安装软件包之前你还要安装 package installer (软件包安装工具),而要安装这个工具你还得先学会如何在你的操作系统下安装软件,真是烦不胜烦呀。

    无论如何,还是克服困难把。你就把它当做进入编程俱乐部的一个考验。每个程序员都会经历这条道路,在每一段“酷”的背后总会有一段“烦”的。

    测试你的配置

    安装了所有上面的软件包以后,你就可以做下面的事情了:

    ~/projects/skeleton $ nosetests
    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.007s
    

    OK

    下一节练习中我会告诉你 nosetests 的功能,不过如果你没有看到上面的画面,那就说明你哪里出错了。确认一下你的 NAME 和 tests 目录下存在 __init__.py, 并且你没有把 tests/NAME_tests.py 命名错。

    使用这个骨架

    剃牦牛的事情已经做的差不多了,以后每次你要新建一个项目时,只要做下面的事情就可以了:

  • 拷贝这份骨架目录,把名字改成你新项目的名字。
  • 再将 NAME 模组更名为你需要的名字,它可以是你项目的名字,当然别的名字也行。
  • 编辑 setup.py 让它包含你新项目的相关信息。
  • 重命名 tests/NAME_tests.py ,让它的名字匹配到你模组的名字。
  • 使用 nosetests 检查有无错误。
  • 开始写代码吧。
  • 小测验

    这节练习没有加分习题,不过需要你做一个小测验:

  • 找文档阅读,学会使用你前面安装了的软件包。
  • 阅读关于 setup.py 的文档,看它里边可以做多少配置。Python 的安装器并不是一个好软件,所以使用起来也非常奇怪。
  • 创建一个项目,在模组目录里写一些代码,并让这个模组可以运行。
  • 在 bin 目录下放一个可以运行的脚本,找材料学习一下怎样创建可以在系统下运行的 Python 脚本。
  • 在你的 setup.py 中加入 bin 这个目录,这样你安装时就可以连它安装进去。
  • 使用 setup.py 安装你的模组,并确定安装的模组可以正常使用,最后使用 pip 将其卸载。
  • Project Versions

    Table Of Contents

    • 习题 46: 一个项目骨架
      • 骨架内容: Linux/OSX
        • Python 软件包的安装
      • 测试你的配置
      • 使用这个骨架
      • 小测验

    Previous topic

    习题 45: 对象、类、以及从属关系

    Next topic

    练习 47: 自动化测试

    This Page

    • Show Source

    Quick search

    Enter search terms or a module, class or function name.

    习题 48: 更复杂的用户输入

    习题 48: 更复杂的用户输入

    你的游戏可能一路跑得很爽,不过你处理用户输入的方式肯定让你不胜其烦了。每一个房间都需要一套自己的语句,而且只有用户完全输入正确后才能执行。你需要一个设备,它可以允许用户以各种方式输入语汇。例如下面的机种表述都应该被支持才对:

    • open door
    • open the door
    • go THROUGH the door
    • punch bear
    • Punch The Bear in the FACE

    也就是说,如果用户的输入和常用英语很接近也应该是可以的,而你的游戏要识别出它们的意思。为了达到这个目的,我们将写一个模组专门做这件事情。这个模组里边会有若干个类,它们互相配合,接受用户输入,并且将用户输入转换成你的游戏可以识别的命令。

    英语的简单格式是这个样子的:

    • 单词由空格隔开。
    • 句子由单词组成。
    • 语法控制句子的含义。

    所以最好的开始方式是先搞定如何得到用户输入的词汇,并且判断出它们是什么。

    我们的游戏语汇

    我在游戏里创建了下面这些语汇:

    • 表示方向: north, south, east, west, down, up, left, right, back.
    • 动词: go, stop, kill, eat.
    • 修饰词: the, in, of, from, at, it
    • 名词: door, bear, princess, cabinet.
    • 数词: 由 0-9 构成的数字。

    说到名词,我们会碰到一个小问题,那就是不一样的房间会用到不一样的一组名词,不过让我们先挑一小组出来写程序,以后再做改进把。

    如何断句

    我们已经有了词汇表,为了分析句子的意思,接下来我们需要找到一个断句的方法。我们对于句子的定义是“空格隔开的单词”,所以只要这样就可以了:

    stuff = raw_input('> ')
    words = stuff.split()
    

    目前做到这样就可以了,不过这招在相当一段时间内都不会有问题。

    语汇元组

    一旦我们知道了如何将句子转化成词汇列表,剩下的就是逐一检查这些词汇,看它们是什么类型。为了达到这个目的,我们将用到一个非常好使的 python 数据结构,叫做”元组(tuple)”。元组其实就是一个不能修改的列表。创建它的方法和创建列表差不多,成员之间需要用逗号隔开,不过方括号要换成圆括号 () :

    first_word = ('direction', 'north')
    second_word = ('verb', 'go')
    sentence = [first_word, second_word]
    

    这样我们就创建了一个 (TYPE, WORD) 组,让你识别出单词,并且对它执行指令。

    这只是一个例子,不过最后做出来的样子也差不多。你接受用户输入,用 split 将其分隔成单词列表,然后分析这些单词,识别它们的类型,最后重新组成一个句子。

    扫描输入

    现在你要写的是词汇扫描器。这个扫描器会将用户的输入字符串当做参数,然后返回由多个 (TOKEN, WORD) 组成的一个列表,这个列表实现类似句子的功能。如果一个单词不在预定的词汇表中,那它返回时 WORD 应该还在,但 TOKEN 应该设置成一个专门的错误标记。这个错误标记将告诉用户哪里出错了。

    有趣的地方来了。我不会告诉你这些该怎样做,但我会写一个“单元测试(unit test)”,而你要把扫描器写出来,并保证单元测试能够正常通过。

    “异常”和数字

    有一件小事情我会先帮帮你,那就是数字转换。为了做到这一点,我们会作一点弊,使用“异常(exceptions)”来做。“异常”指的是你运行某个函数时得到的错误。你的函数在碰到错误时,就会“提出(raise)”一个“异常”,然后你就要去处理(handle)这个异常。假如你在python 里写了这些东西:

    ~/projects/simplegame $ python
    Python 2.6.5 (r265:79063, Apr 16 2010, 13:57:41)
    [GCC 4.4.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> int("hell")
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ValueError: invalid literal for int() with base 10: 'hell'
    >>
    

    这个 ValueError 就是 int() 函数抛出的一个异常。因为你给 int() 的参数不是一个数字。 int() 函数其实也可以返回一个值来告诉你它碰到了错误,不过由于它只能返回整数值,所以很难做到这一点。它不能返回 -1,因为这也是一个数字。 int() 没有纠结在它“究竟应该返回什么”上面,而是提出了一个叫做 ValueError 的异常,然后你只要处理这个异常就可以了。

    处理异常的方法是使用 try 和 except 这两个关键字:

    def convert_number(s):
     try:
      return int(s)
     except ValueError:
      return None
    

    你把要试着运行的代码放到 try 的区段里,再将出错后要运行的代码放到 except 区段里。在这里,我们要试着调用 init() 去处理某个可能是数字的东西,如果中间出了错,我们就抓到这个错误,然后返回 None。

    在你写的扫描器里面,你应该使用这个函数来测试某个东西是不是数字。做完这个检查,你就可以声明这个单词是一个错误单词了。

    你应该测试的东西

    这里是你应该使用的测试文件 tests/lexicon_tests.py :

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    from nose.tools import *
    from ex48 import lexicon
    

    def test_directions():
    assert_equal(lexicon.scan("north"), [('direction', 'north')])
    result = lexicon.scan("north south east")
    assert_equal(result, [('direction', 'north'),
    ('direction', 'south'),
    ('direction', 'east')])

    def test_verbs():
    assert_equal(lexicon.scan("go"), [('verb', 'go')])
    result = lexicon.scan("go kill eat")
    assert_equal(result, [('verb', 'go'),
    ('verb', 'kill'),
    ('verb', 'eat')])

    def test_stops():
    assert_equal(lexicon.scan("the"), [('stop', 'the')])
    result = lexicon.scan("the in of")
    assert_equal(result, [('stop', 'the'),
    ('stop', 'in'),
    ('stop', 'of')])

    def test_nouns():
    assert_equal(lexicon.scan("bear"), [('noun', 'bear')])
    result = lexicon.scan("bear princess")
    assert_equal(result, [('noun', 'bear'),
    ('noun', 'princess')])

    def test_numbers():
    assert_equal(lexicon.scan("1234"), [('number', 1234)])
    result = lexicon.scan("3 91234")
    assert_equal(result, [('number', 3),
    ('number', 91234)])

    def test_errors():
    assert_equal(lexicon.scan("ASDFADFASDF"), [('error', 'ASDFADFASDF')])
    result = lexicon.scan("bear IAS princess")
    assert_equal(result, [('noun', 'bear'),
    ('error', 'IAS'),
    ('noun', 'princess')])

    记住你要使用你的项目骨架来创建新项目,将这个测试用例写下来(不许复制粘贴!),然后编写你的扫描器,直至所有的测试都能通过。注意细节并确认结果一切工作良好。

    设计的技巧

    集中一次实现一个测试项目,尽量保持项目简单,只要把你的 lexicon.py 词汇表中所有的单词放那里就可以了。不要修改输入的单词表,不过你需要创建自己的新列表,里边包含你的语汇元组。另外,记得使用 in 关键字来检查这些语汇列表,以确认某个单词是否在你的语汇表中。

    加分习题

  • 改进单元测试,让它覆盖到更多的语汇。
  • 向语汇列表添加更多的语汇,并且更新单元测试代码。
  • 让你的扫描器能够识别任意大小写的词汇。更新你的单元测试以确认其功能。
  • 找出另外一种转换为数字的方法。
  • 我的解决方案用了 37 行代码,你的是更长还是更短呢?
  • Project Versions

    Table Of Contents

    • 习题 48: 更复杂的用户输入
      • 我们的游戏语汇
        • 如何断句
        • 语汇元组
        • 扫描输入
        • “异常”和数字
      • 你应该测试的东西
      • 设计的技巧
      • 加分习题

    Previous topic

    练习 47: 自动化测试

    Next topic

    习题 49: 创建句子

    This Page

    • Show Source

    Quick search

    Enter search terms or a module, class or function name.