"Learn Python the Hard Way"学习笔记8——Exercise44-Exercise48

Exercise44 继承和包含

当你写下class Foo(Bar)的时候,就发生了继承,这句代码的意思是“创建一个叫做Foo的类,并继承Bar” 。当你执行这句的时候,编程语言使得Foo的实例所有的行为都跟Bar的实例一样。
父子类之间有3种交互方法:

1.子类的方法隐性继承父类方法
2.子类重写父类的方法
3.对子类的操作改变父类

隐性继承
class Parent(object):
    
    def implicit(self):
        print "PARENT implicit()"
        
class Child(Parent):
    pass 
    
dad = Parent()
son = Child()

dad.implicit()
son.implicit()

执行结果:


output44a.png

父类中定义了一个函数,而在子类中虽然没有定义同样名称的函数,但在子类的实例上也可以用此函数。

重写函数
class Parent(object):
    
    def override(self):
        print "PARENT override()"
        
   
class Child(Parent):

    def override(self):
        print "CHILD override()"

dad = Parent()
son = Child()

dad.override()
son.override()

执行结果:

output44b.png

如果父类和子类对某个函数有不同的定义,当它们的实例执行这个函数时,分别执行相应的定义。

改变之前&之后
class Parent(object):

    def altered(self):
        print "PARENT altered()"
        
class Child(Parent):
    
    def altered(self):
        print "CHILD, BEFORE PARENT altered()"
        super(Child, self).altered()
        print "CHILD, AFTER PARENT altered()"
        
dad = Parent()
son = Child()
 
dad.altered()
son.altered()

执行结果:

output44c.png

这里的第九行获得了父类的之前行为,所以可以看到结果中给出了父类版本的方法执行行为前后的提示。

上述三个的结合体
class Parent(object):

    def override(self):
        print "PARENT override()"
     
    def implicit(self):
        print "PARENT implicit()"
        
    def altered(self):
        print "PARENT altered()"
        
class Child(Parent):
    
    def override(self):
        print "CHILD override()"
        
    def altered(self):
        print "CHILD, BEFORE PARENT altered()"
        super(Child, self).altered()
        print "CHILD, AFTER PARENT altered()"
        
dad = Parent()
son = Child()

dad.implicit()
son.implicit()

dad.override()
son.override()

dad.altered()
son.altered()
包含
lass Other(object):
    
    def override(self):
        print "OTHER override()"
        
    def implicit(self):
        print "OTHER implicit()"
        
    def altered(self):
        print "OTHER altered()"
        
class Child(object):

    def __init__(self):
        self.other = Other()
        
    def implicit(self):
        self.other.implicit()
    
    def override(self):
        print "CHILD override()"
        
    def altered(self):
        print "CHILD, BEFORE OTHER altered()"
        self.other.altered()
        print "CHILD, AFTER OTHER altered()"
        
son = Child()

son.implicit()
son.override()
son.altered()

执行结果:

output44e.png

不使用继承的方式,实现前三个例子同样的操作。

什么时候用继承,什么时候用包含

三个指导准则:

1.不惜一切代价避免多重继承,因为它太复杂太不可靠。如果你必须要使用它,那么一定要知道类的层次结构,并花时间找到每一个类是从哪里来的。
2.将代码封装为模块,这样就可以在许多不同的地方或情况使用。
3.只有当有明显相关的可重用的代码,且在一个共同概念下时,可以使用继承。

作业:阅读网页https://www.python.org/dev/peps/pep-0008/,python代码规范

Exercise 45 制作你的游戏

(写得很垃圾,不放了)

Exercise 46 项目骨架

安装python的包:参考的http://www.jb51.net/article/70331.htm,两种方法都可行。
在ex46文件夹创建projects目录,setup.py、NAME_tests.py代码:

#setup.py
try:
    from setuptools import setup
except ImportError:
    from distutils.core import setup

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

setup(**config)
#NAME_tests.py
from nose.tools import *
import NAME

def setup():
    print "SETUP!"

def teardown():
    print "TEAR DOWN!"

def test_basic():
    print "I RAN!"

最后整个项目的结构如下:


output46.png

Exercise 47 自动测试

为了确认游戏的功能是否正常,你需要一遍一遍地在你的游戏中输入命令。这个过程是很枯燥无味的。如果能写一小段代码用来测试你的代码岂不是更好?然后只要你对程序做了任何修改,或者添加了什么新东西,你只要“跑一下你的测试”,而这些测试能确认程序依然能正确运行。这些自动测试不会抓到所有的 bug,但可以让你无需重复输入命令运行你的代码,从而为你节约很多时间。

复制ex46的整个项目骨架skeleton文件夹到ex47,把所有的NAME改成ex47,删掉.pyc文件。
新建一个文件 ex47/game.py(用来被测试,这里的ex47文件夹指的是skeleton内部的ex47文件夹,不是最外层的ex47):

#game.py
class Room(object):
    
    def __init__(self, name, description):
        self.name = name
        self.description = description
        self.paths = {}
        
    def go(self, direction):
        return self.paths.get(direction, None)
        
    def add_paths(self, paths):
        self.paths.update(paths)

把测试骨架改成这个:

#ex47_tests.py
from nose.tools import *
from ex47.game import Room


def test_room():
    gold = Room("GoldRoom",
                """This room has gold in it you can grab. There's a 
                door to the north.""")
    assert_equal(gold.name, "GoldRoom")               
    assert_equal(gold.paths, {})
    
def test_room_paths():
    center = Room("Center", "Test room in the center.")
    north = Room("North", "Test room in the north.")
    south = Room("South", "Test room in the south.")
    
    center.add_paths({'north': north, 'south': south})
    assert_equal(center.go('north'), north)
    assert_equal(center.go('south'), south)

def test_map():
    start = Room("Start", "You can go west and down a hole.")
    west = Room("Trees", "There are trees here, you can go east.")
    down = Room("Dungeon", "It's a dark down here, you can go up.")
    start.add_paths({'west': west, 'down': down})
    west.add_paths({'east': start})
    down.add_paths({'up': start})
    
    assert_equal(start.go('west'), west)
    assert_equal(start.go('west').go('east'), start)
    assert_equal(start.go('down').go('up'), start)

这个部分的两个程序改了很久才通过,其中书上的[]都需要改成{},执行结果:


output47.png

Exercise 48 进阶输入

这部分书上先给了两个提示:
1.怎么断句
2.元组结构
然后让我们实现一个scanner,功能是扫描用户输入,输出的是输入句子中每个单词的词性和它本身。写出来的程序需要能通过测试lexicon_test.py。

##lexicon_test.py
from nose.tools import *
from ex48 import lexicon

def test_direction():
    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_stop():
    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("ASDFABC"), [('error', 'ASDFABC')])
    result = lexicon.scan("bear IAS princess")
    assert_equal(result, [('noun', 'bear'),
                          ('error', 'IAS'),
                          ('noun', 'princess')])                          

我写的程序:

#lexicon.py
direction = ['north', 'south', 'east', 'west', 'down', 'up', 'left', 'right', 'back']
verb = ['go', 'stop', 'kill', 'eat']
stop = ['the', 'in', 'of', 'from', 'at', 'it']
noun = ['door', 'bear', 'princess', 'cabinet']

def scan(stuff):
    words = stuff.split()
    t = list()
    for word in words:
        try:
            word = int(word)
            t.append(('number', word))
        except:
            if word in direction:
                t.append(('direction', word))
            elif word in verb:
                t.append(('verb', word))
            elif word in stop:
                t.append(('stop', word))
            elif word in noun:
                t.append(('noun', word))
            else:
                t.append(('error', word))      
    return t                

用命令行运行所有的测试结果都正确,但是一开始运行nosetests总是出现问题,测试卡住。睡了一觉起来就好了= =,调程序是门玄学。


result48.png
output48.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,670评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,928评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,926评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,238评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,112评论 4 356
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,138评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,545评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,232评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,496评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,596评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,369评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,226评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,600评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,906评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,185评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,516评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,721评论 2 335

推荐阅读更多精彩内容

  • 要点: 函数式编程:注意不是“函数编程”,多了一个“式” 模块:如何使用模块 面向对象编程:面向对象的概念、属性、...
    victorsungo阅读 1,447评论 0 6
  • 22年12月更新:个人网站关停,如果仍旧对旧教程有兴趣参考 Github 的markdown内容[https://...
    tangyefei阅读 35,156评论 22 257
  • python学习笔记 声明:学习笔记主要是根据廖雪峰官方网站python学习学习的,另外根据自己平时的积累进行修正...
    renyangfar阅读 3,004评论 0 10
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,505评论 18 399
  • 一直带着一点压抑的情绪看电影《雄狮》,在25年后的家乡,当萨罗和白发苍苍的老母亲紧紧拥抱在一起的时候,泪水终于决堤...
    嘉陵客人阅读 755评论 2 6