🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
# 习题 42: 物以类聚 虽说将函数放到字典里是很有趣的一件事情,你应该也会想到“如果 Python 能自动为你做这件事情该多好”。事实上也的确有,那就是 class 这个关键字。你可以使用 class 创建更棒的“函数字典”,比你在上节练习中做的强大多了。Class(类)有着各种各样强大的功能和用法,但本书不会深入讲这些内容,在这里,你只要你学会把它们当作高级的“函数字典”使用就可以了。 用到“class”的编程语言被称作“Object Oriented Programming(面向对象编程)”语言。这是一种传统的编程方式,你需要做出“东西”来,然后你“告诉”这些东西去完成它们的工作。类似的事情你其实已经做过不少了,只不过还没有意识到而已。记得你做过的这个吧: ~~~ stuff = ['Test', 'This', 'Out'] print ' '.join(stuff) ~~~ 其实你这里已经使用了 class。stuff 这个变量其实是一个 listclass (列表类)。而 ''.join(stuff) 里调用函数 join 的字符串 '' (就是一个空格)也是一个 class —— 它是一个 string class (字符串类)。到处都是 class! 还有一个概念是 object(物件),不过我们暂且不提。当你创建过几个 class 后就会学到了。你怎样创建 class 呢?和你创建 ROOMS 的方法差不多,但其实更简单: <table class="highlighttable"><tbody><tr><td class="linenos"> <div class="linenodiv"> <pre> 1&#13; 2&#13; 3&#13; 4&#13; 5&#13; 6&#13; 7&#13; 8&#13; 9&#13; 10&#13; 11&#13; 12&#13; 13&#13; 14&#13; 15&#13; 16&#13; 17&#13; 18&#13; 19&#13; 20&#13; 21&#13; 22&#13; 23&#13; 24&#13; 25&#13; 26&#13; 27&#13; 28&#13; 29&#13; 30&#13; 31&#13; 32&#13; 33&#13; 34&#13; 35&#13; 36&#13; 37</pre> </div> </td> <td class="code"> <div class="highlight"> <pre>class TheThing(object):&#13; &#13; def __init__(self):&#13; self.number = 0&#13; &#13; def some_function(self):&#13; print "I got called."&#13; &#13; def add_me_up(self, more):&#13; self.number += more&#13; return self.number&#13; &#13; # two different things&#13; a = TheThing()&#13; b = TheThing()&#13; &#13; a.some_function()&#13; b.some_function()&#13; &#13; print a.add_me_up(20)&#13; print b.add_me_up(30)&#13; &#13; print a.number&#13; print b.number&#13; &#13; # Study this. This is how you pass a variable&#13; # from one class to another. You will need this.&#13; class TheMultiplier(object):&#13; &#13; def __init__(self, base):&#13; self.base = base&#13; &#13; def do_it(self, m):&#13; return m * self.base&#13; &#13; x = TheMultiplier(a.number)&#13; print x.do_it(b.number)&#13; </pre> </div> </td> </tr></tbody></table> Warning 嗯,你开始看到 Python 的“疣子”了。Python 是一门比较旧的语言,其中包含很多丑陋的设计决定。为了将这些丑陋设计掩盖过去,他们就做了一些新的丑陋设计,然后告诉人们让他们习惯这些新的坏设计。classTheThing(object) 就是其中一个例子。这里我就不展开讲了,不过你也不必操心为什么你的 class 要在后面添一个(object) ,只要跟着这样做就可以了,否则将来总有一天别的 Python 程序员会吼你让你这样做。后面我们再讲为什么。 你看到参数里的 self 了吧?你知道它是什么东西吗?对了,它就是 Python 创建的额外的一个参数,有了它你才能实现 a.some_function()`这种用法,这时它就会把\前者翻译成``some_function(a) 执行下去。为什么用 self 呢?因为你的函数并不知道你的这个“实例”是来自叫 TheThing 或者别的名字的 class。所以你只要使用一个通用的名字 self 。这样你写出来的函数就会在任何情况下都能正常工作。 其实你可以使用 self 以外的别的字眼,不过如果你这样做的话,你就会成为所有Python 程序员的众之矢的,所以还是随大流的好。只有变态才会在这里乱改,我教你的没错。对以后会读到你的代码的人好点儿,因为你现在的代码10年以后所有的代码都会是一团糟。 接下来,看到 __init__ 函数了吗?这就是你为 Python class 设置内部变量的方式。你可以使用 . 将它们设置到 self 上面。另外看到我们使用了 add_me_up() 为你创建的 self.number 加值。后面你可以看到我们怎样可以使用这种方法为数字加值,然后打印出来。 接着我创建了另一个叫 TheMutiplier 的 class,它的功能是做乘法。这样的 class 其实是非常没必要的,不过它向你展示了如何将变量和状态从一个 class 传递到另一个 class。在这里我使用了 TheMultiplier.__init__ 来从 a.number 来获取基本数值,我还将 b.number 传递到 TheMultiplier.do_it 以供调用。好好研究一下,你需要相关的知识来完成后面的加分习题。 Class 是很强大的东西,你应该好好读读相关的东西。尽可能多找些东西读并且多多实验。你其实知道它们该怎么用,只要试试就知道了。其实我马上就要去练吉他了,所以我不会让你写练习了。你将使用 class 写一个练习。 接下来我们将把习题41的内容重写,不过这回我们将使用 class: <table class="highlighttable"><tbody><tr><td class="linenos"> <div class="linenodiv"> <pre> 1&#13; 2&#13; 3&#13; 4&#13; 5&#13; 6&#13; 7&#13; 8&#13; 9&#13; 10&#13; 11&#13; 12&#13; 13&#13; 14&#13; 15&#13; 16&#13; 17&#13; 18&#13; 19&#13; 20&#13; 21&#13; 22&#13; 23&#13; 24&#13; 25&#13; 26&#13; 27&#13; 28&#13; 29&#13; 30&#13; 31&#13; 32&#13; 33&#13; 34&#13; 35&#13; 36&#13; 37&#13; 38&#13; 39&#13; 40&#13; 41&#13; 42&#13; 43&#13; 44&#13; 45&#13; 46&#13; 47&#13; 48&#13; 49&#13; 50&#13; 51&#13; 52&#13; 53&#13; 54&#13; 55&#13; 56&#13; 57&#13; 58&#13; 59&#13; 60&#13; 61&#13; 62&#13; 63&#13; 64&#13; 65&#13; 66&#13; 67&#13; 68&#13; 69&#13; 70&#13; 71&#13; 72&#13; 73&#13; 74&#13; 75&#13; 76</pre> </div> </td> <td class="code"> <div class="highlight"> <pre>## Animal is-a object (yes, sort of confusing) look at the extra credit&#13; class Animal(object):&#13; pass&#13; &#13; ## ??&#13; class Dog(Animal):&#13; &#13; def __init__(self, name):&#13; ## ??&#13; self.name = name&#13; &#13; ## ??&#13; class Cat(Animal):&#13; &#13; def __init__(self, name):&#13; ## ??&#13; self.name = name&#13; &#13; ## ??&#13; class Person(object):&#13; &#13; def __init__(self, name):&#13; ## ??&#13; self.name = name&#13; &#13; ## Person has-a pet of some kind&#13; self.pet = None&#13; &#13; ## ??&#13; class Employee(Person):&#13; &#13; def __init__(self, name, salary):&#13; ## ?? hmm what is this strange magic?&#13; super(Employee, self).__init__(name)&#13; ## ??&#13; self.salary = salary&#13; &#13; ## ??&#13; class Fish(object):&#13; pass&#13; &#13; ## ??&#13; class Salmon(Fish):&#13; pass&#13; &#13; ## ??&#13; class Halibut(Fish):&#13; pass&#13; &#13; &#13; ## rover is-a Dog&#13; rover = Dog("Rover")&#13; &#13; ## ??&#13; satan = Cat("Satan")&#13; &#13; ## ??&#13; mary = Person("Mary")&#13; &#13; ## ??&#13; mary.pet = satan&#13; &#13; ## ??&#13; frank = Employee("Frank", 120000)&#13; &#13; ## ??&#13; frank.pet = rover&#13; &#13; ## ??&#13; flipper = Fish()&#13; &#13; ## ??&#13; crouse = Salmon()&#13; &#13; ## ??&#13; harry = Halibut()&#13; </pre> </div> </td> </tr></tbody></table> ### 你应该看到的结果 这个版本的游戏和你的上一版效果应该是一样的,其实有些代码都几乎一样。比较一下两版代码,弄懂其中不同的地方,重点需要理解这些东西: 1. 怎样创建一个 classGame(object) 并且放函数到里边去。 1. __init__ 是一个特殊的初始方法,可以预设重要的变量在里边。 1. 为 class 添加函数的方法是将函数在 class 下再缩进一阶,class 的架构就是通过缩进实现的,这点很重要。 1. 你在函数里的内容又缩进了一阶。 1. 注意冒号的用法。 1. 理解 self 的概念,以及它在 __init__ 、 play 、 death 里是怎样使用的。 1. 研究 play 里的 getattr 的功能,这样你就能明白 play 所做的事情。其实你可以手动在 Python 命令行实验一下,从而弄懂它。 1. 最后我们怎样创建了一个 Game ,然后通过 play() 让所有的东西运行起来。 ### 加分习题 1. 研究一下 __dict__ 是什么东西,应该怎样使用。 1. 再为游戏添加一些房间,确认自己已经学会使用 class 。 1. 创建一个新版本,里边使用两个 class,其中一个是 Map ,另一个是 Engine 。提示: 把 play 放到 Engine 里面。