美文网首页
"Learn Python the Hard Way"学习笔记8

"Learn Python the Hard Way"学习笔记8

作者: los_pollos | 来源:发表于2017-11-20 10:32 被阅读0次

    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

    相关文章

      网友评论

          本文标题:"Learn Python the Hard Way"学习笔记8

          本文链接:https://www.haomeiwen.com/subject/qsbqmxtx.html