习题 42: 对象、类、以及从属关系 ********************************************* 有一个重要的概念你需要弄明白,那就是“类(class)”和“对象(object)”的区别。\ 问题在于,class 和 object 并没有真正的不同。它们其实是同样的东西,只是在不同的时间\ 名字不同罢了。我用禅语来解释一下吧: ``鱼和泥鳅有什么区别?`` 这个问题有没有让你有点晕呢?说真的,坐下来想一分钟。我的意思是说,鱼和泥鳅是不一样,\ 不过它们其实也是一样的是不是?泥鳅是鱼的一种,所以说没什么不同,不过泥鳅又有些特别,\ 它和别的种类的鱼的确不一样,比如泥鳅和黄鳝就不一样。所以泥鳅和鱼既相同又不同。\ 怪了。 这个问题让人晕的原因是大部分人不会这样去思考问题,其实每个人都懂这一点,你无须去思考\ 鱼和泥鳅的区别,因为你知道它们之间的关系。你知道泥鳅是鱼的一种,而且鱼还有别的种类,\ 根本就没必要去思考这类问题。 让我们更进一步,假设你有一只水桶,里边有三条泥鳅。假设你的好人卡多到没地方用,于是\ 你给它们分别取名叫小方,小斌,小星。现在想想这个问题: ``小方和泥鳅有什么区别?`` 这个问题一样的奇怪,但比起鱼和泥鳅的问题来还好点。你知道小方是一条泥鳅,所以他并没什么\ 不同,他只是泥鳅的一个“实例(instance)”。小斌和小星一样也是泥鳅的实例。我的意思是说,它们\ 是由泥鳅创建出来的,而且代表着和泥鳅一样的属性。 所以我们的思维方式是(你可能会有点不习惯):鱼是一个“类(class)”,泥鳅是一个“类(class)”,\ 而小方是一个“对象(object)”。仔细想想,然后我再一点一点慢慢解释给你。 鱼是一个“类”,表示它不是一个真正的东西,而是一个用来描述具有同类属性的实例的概括性词汇。 你有鳍?你有鳔?你住在水里?好吧那你就是一条鱼。 后来河蟹养殖专家路过,看到你的水桶,于是告诉你:“小伙子,你这些鱼是泥鳅。” 专家一出,\ 真相即现。并且专家还定义了一个新的叫做“泥鳅”的“类”,而这个“类”又有它特定的属性。\ 细长条?有胡须?爱钻泥巴?吃起来味道还可以?那你就是一条泥鳅。 最后家庭煮父过来了,他跟河蟹专家说:“非也非也,你看到的是泥鳅,我看到的是小方,而且\ 我要把小方和剁椒配一起做一道小菜。”于是你就有了一只叫做小方的泥鳅的“实例(instance)”\ (泥鳅也是鱼的一个“实例”),并且你使用了它(把它塞到你的胃里了),这样它就是一个\ “对象(object)”。 这会你应该了解了:小方是泥鳅的成员,而泥鳅又是鱼的成员。这里的关系式:对象属于某个类,\ 而某个类又属于另一个类。 写成代码是什么样子 ---------------------- 这个概念有点绕人,不过实话说,你只要在创建和使用 class 的时候操心一下就可以了。\ 我来给你两个区分 ``Class`` 和 ``Object`` 的小技巧。 首先针对类和对象,你需要学会两个说法,“is-a(是啥)”和“has-a(有啥)”。“是啥”要用在\ 谈论“两者以类的关系互相关联”的时候,而“有啥”要用在“两者无共同点,仅是互为参照”的时候。 接下来,通读这段代码,将每一个注解为 ``##??`` 的位置标明他是“is-a”还是“has-a”\ 的关系,并讲明白这个关系是什么。在代码的开始我还举了几个例子,所以你只要写\ 剩下的就可以了。 记住,“是啥”指的是鱼和泥鳅的关系,而“有啥”指的是泥鳅和鳃的关系。 (译注:为了解释方便,译文使用了中文鱼名。原文使用的是“三文鱼(salmon)”和\ “大比目鱼(halibut)”,名字也是英文常用人名。) .. literalinclude:: ex/ex45.py :linenos: 关于 class Name(object) ======================== 记得我曾经强迫让你使用 ``class Name(object)`` 却没告诉你为什么吧,现在你已经\ 知道了“类”和“对象”的区别,我就可以告诉你原因了。如果我早告诉你的话,你可能会\ 晕掉,也学不会这门技术了。 真正的原因是在 Python 早期,它对于 ``class`` 的定义在很多方面都是严重有问题的。\ 当他们承认这一点的时候已经太迟了,所以逼不得已,他们需要支持这种有问题的 ``class``\。\ 为了解决已有的问题,他们需要引入一种“新类”,这样的话“旧类”还能继续使用,而你也\ 有一个新的正确的类可以使用了。 这就用到了“类即是对象”的概念。他们决定用小写的“object”这个词作为一个类,让你在\ 创建新类时从它继承下来。有点晕了吧?一个类从另一个类继承,而后者虽然是个类,但\ 名字却叫“object”……不过在定义类的时候,别忘记要从 object 继承就好了。 的确如此。一个词的不同就让这个概念变得更难理解,让我不得不现在才讲给你。现在你\ 可以试着去理解“一个是对象的类”这个概念了,如果你感兴趣的话。 不过我还是建议你别去理解了,干脆完全忘记旧格式和新格式类的区别吧,就假设 Python 的 class 永远都要求你加上 (object) 好了,你的脑力要留着思考更重要的问题。 加分习题 ============ 1. 研究一下为什么 Python 添加了这个奇怪的叫做 ``object`` 的 class,它究竟有什么\ 含义呢? 2. 有没有办法把 ``Class`` 当作 ``Object`` 使用呢? 3. 在习题中为 animals、fish、还有 people 添加一些函数,让它们做一些事情。看看\ 当函数在 Animal 这样的“基类(base class)”里和在 Dog 里有什么区别。 4. 找些别人的代码,理清里边的“是啥”和“有啥”的关系。 5. 使用列表和字典创建一些新的一对应多的“has-many”的关系。 6. 你认为会有一种“has-many”的关系吗?阅读一下关于“多重继承(multiple inheritance)”\ 的资料,然后尽量避免这种用法。 常见问题回答 ========================== 这些 ``## ??`` 注解是干嘛用的? 这些注解是供你填空的。你应该在对应的位置填入“is-a”、“has-a”的概念。重读这节习题,看看其它\ 的注解,仔细理解一下我的意思。 这句 ``self.pet = None`` 有什么用? 确保类的 ``self.pet`` 属性被设置为 ``None``\。 ``super(Employee, self).__init__(name)`` 是做什么用的? 这样你可以可靠地将父类的 ``__init__`` 方法运行起来。搜索“python super”,看看它的优缺点。