笨办法学Python 习题 42: 对象、类、以及从属关系

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

鱼和三文鱼有什么区别?

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

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

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

Mary和三文鱼有什么区别?

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

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

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

后来河蟹养殖专家路过,看到你的水桶,于是告诉你:“小伙子,你这些鱼是三文鱼。” 并且专家还定义了一个新的叫做“三文鱼”的“类”,而这个“类”又有它特定的属性。长鼻子?浅红色的肉?生活在海洋里?吃起来味道还可以?那你就是一条三文鱼。

最后一个厨师过来了,他跟专家说:“非也非也,你看到的是三文鱼,我看到的是Mary,而且我要把Mary和剁椒配一起做一道小菜。”于是你就有了一只叫做Mary的三文鱼的“实例(instance)”(三文鱼也是鱼的一个“实例”),并且你使用了它,这样它就是一个“对象(object)”。

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

写成代码是什么样子

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

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

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

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

# -*- coding:utf-8 -*-
## 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) 好了,你的脑力要留着思考更重要的问题。

附加题

1.研究一下为什么Python添加了这个奇怪的叫做object的类,它究竟有什么含义呢?

2.有没有办法把Class当作Object使用呢?

3.在习题中为 animals、fish、还有 people 添加一些函数,让它们做一些事情。看看当函数在 Animal 这样的“基类(base class)”里和在 Dog 里有什么区别。

4.找些别人的代码,理清里边的“是啥”和“有啥”的关系。

5.使用列表和字典创建一些新的一对应多的“has-many”的关系。

6.你认为会有一种“has-many”的关系吗?阅读一下关于“多重继承(multiple inheritance)”的资料,然后尽量避免这种用法。

常见问题

Q: 这些注释符## ??是干什么的?

这些是你需要完成的“填空”,你需要填上 "is-a"或者 "has-a"。再读一遍本节练习,看看其他的注释,弄明白我再说什么。

Q: self.pet = None是什么意思?

确保给self.pet设置了一个默认值None

Q: super(Employee,self).__init__(name)实现了什么?

这是用来执行父类的__init__方法的,上网搜索一下“python super”相关文档,阅读文档的各种建议。


版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Python中的函数(二) 在上一篇文章中提到了Python中函数的定义和使用,在这篇文章里我们来讨论下关于函数的一些更深的话题。在学习C语言函数的时候,遇到的问题主要有形参实参的区别、参数的传递和改变、变量的作用域。同样在Python中,关于对函数的理解和使用也存在这些问题。下面来逐一讲解。一.函
Python中的字符串 可能大多数人在学习C语言的时候,最先接触的数据类型就是字符串,因为大多教程都是以"Hello world"这个程序作为入门程序,这个程序中要打印的"Hello world"就是字符串。如果你做过自然语言处理方面的研究,并且用Python
Python 面向对象编程(一) 虽然Python是解释性语言,但是它是面向对象的,能够进行对象编程。下面就来了解一下如何在Python中进行对象编程。一.如何定义一个类 在进行python面向对象编程之前,先来了解几个术语:类,类对象,实例对象,属性,函数和方法。 类是对现实世界中一些事物的封装,
Python面向对象编程(二) 在前面一篇文章中谈到了类的基本定义和使用方法,这只体现了面向对象编程的三大特点之一:封装。下面就来了解一下另外两大特征:继承和多态。 在Python中,如果需要的话,可以让一个类去继承一个类,被继承的类称为父类或者超类、也可以称作基类,继承的类称为子类。并且Pytho
Python中的函数(一) 接触过C语言的朋友对函数这个词肯定非常熟悉,无论在哪门编程语言当中,函数(当然在某些语言里称作方法,意义是相同的)都扮演着至关重要的角色。今天就来了解一下Python中的函数用法。一.函数的定义 在某些编程语言当中,函数声明和函数定义是区分开的(在这些编程语言当中函数声明
在windows下如何快速搭建web.py开发框架 用Python进行web开发的话有很多框架供选择,比如最出名的Django,tornado等,除了这些框架之外,有一个轻量级的框架使用起来也是非常方便和顺手,就是web.py。它由一名黑客所创建,但是不幸的是这位创建者于2013年自杀了。据说现在由
将Sublime Text 2搭建成一个好用的IDE 说起编辑器,可能大部分人要推荐的是Vim和Emacs,本人用过Vim,功能确实强大,但是不是很习惯,之前一直有朋友推荐SUblime Text 2这款编辑器,然后这段时间就试了一下,就深深地喜欢上这款编辑器了...
Python中的模块 有过C语言编程经验的朋友都知道在C语言中如果要引用sqrt这个函数,必须用语句"#include<math.h>"引入math.h这个头文件,否则是无法正常进行调用的。那么在Python中,如果要引用一些内置的函数,该怎么处理呢?在Python中
Python的基础语法 在对Python有了基础的认识之后,下面来了解一下Python的基础语法,看看它和C语言、java之间的基础语法差异。一.变量、表达式和语句 Python中的语句也称作命令,比如print "hello python"这就是一条语句。 表达式,顾名思义,是
Eclipse+PyDevʽjango+Mysql搭建Python web开发环境 Python的web框架有很多,目前主流的有Django、Tornado、Web.py等,最流行的要属Django了,也是被大家最看好的框架之一。下面就来讲讲如何搭建Django的开发环境。一.准备工作 需要下载的
在windows下安装配置Ulipad 今天推荐一款轻便的文本编辑器Ulipad,用来写一些小的Python脚本非常方便。 Ulipad下载地址: https://github.com/limodou/ulipad http://files.cnblogs.com/dolphin0520/u...
Python中的函数(三) 在前面两篇文章中已经探讨了函数的一些相关用法,下面一起来了解一下函数参数类型的问题。在C语言中,调用函数时必须依照函数定义时的参数个数以及类型来传递参数,否则将会发生错误,这个是严格进行规定的。然而在Python中函数参数定义和传递的方式相比而言就灵活多了。一.函数参数的
在Notepad++中搭配Python开发环境 Python在最近几年一度成为最流行的语言之一,不仅仅是因为它简洁明了,更在于它的功能之强大。它不仅能够完成一般脚本语言所能做的事情,还能很方便快捷地进行大规模的项目开发。在学习Python之前我们来看一下Python的历史由来,"Pytho
Python中的条件选择和循环语句 同C语言、Java一样,Python中也存在条件选择和循环语句,其风格和C语言、java的很类似,但是在写法和用法上还是有一些区别。今天就让我们一起来了解一下。一.条件选择语句 Python中条件选择语句的关键字为:if 、elif 、else这三个。其基本形式如
关于raw_input( )和sys.stdin.readline( )的区别 之前一直认为用raw_input( )和sys.stdin.readline( )来获取输入的效果完全相同,但是最近在写程序时有类似这样一段代码:import sysline = sys.stdin.readline()
初识Python 跟学习所有的编程语言一样,首先得了解这门语言的编程风格和最基础的语法。下面就让我们一起来了解一下Python的编程风格。1.逻辑行与物理行 在Python中有逻辑行和物理行这个概念,物理行是指在编辑器中实际看到的一行,逻辑行是指一条Python语句。在Python中提倡一个物理行只
当我们的代码是有访问网络相关的操作时,比如http请求或者访问远程数据库,经常可能会发生一些错误,有些错误可能重新去发送请求就会成功,本文分析常见可能需要重试的场景,并最后给出python代码实现。
1.经典迭代器 2.将Sentence中的__iter__改成生成器函数 改成生成器后用法不变,但更加简洁。 3.惰性实现 当列表比较大,占内存较大时,我们可以采用惰性实现,每次只读取一个元素到内存。 或者使用更简洁的生成器表达式 4.yield from itertools模块含有大量生成器函数可
本文介绍简单介绍socket的常用函数,并以python-kafka中的源码socketpair为例,来讲解python socket的运用
python实践中经常出现编码相关的异常,大多网上找资料而没有理解原理,导致一次次重复错误。本文对常用Unicode、UTF-8、GB2312编码的原理进行介绍,接着介绍了python字符类型unicode和str以及常见编解码错误UnicodeEncodeError和UnicodeDEcodeEr