首先要明白几个概念:
- 类:class,是抽象的模板;
- 实例:instance,是基于类的具体的一个例子;
- 一个类里边,既有“属性”,也有“方法”,属性比如说:年龄、性别、婚姻等等,方法是对特定属性的加工、处理等。
- 创建实例:
bart = Student('Bart Simpson', 59); bart的数据类型就是“Student类”;
理解:其实Student这个类,就是一个模板,一种算法,而我们创建的实例对象bart,是bart变量指向的存储单元存储了:
1.指向Student这个类的地址;
2..('Bart Simpson', 59)这组信息。
再次理解:bart.方法 = Student('Bart Simpson', 59).方法; - 实例变量名:上边的bart就是一个实例变量名,他被链接到class 中的 self上;
- 隐藏某个属性或字段:__name、__gender等,请参考:廖雪峰“访问限制”;
- 继承、重写→多态:父类有的“方法”子类就会继承,当然也可以在子类中修改该“方法”从而覆盖父类的方法,从而产生某一属性的多种样态,即多态。
- 对于数据类型的理解:
- 当我们定义一个class的时候,我们实际上就定义了一种数据类型(可见通过class可以定义很多种数据类型)。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样:
a = list() # a是list类型 b = Animal() # b是Animal类型 可见,每一个具体的class就是一个具体的类型 c = Dog() # c是Dog类型 且Dog是Animal的子类
判断一个变量是否是某个类型可以用
isinstance()
判断:>>> isinstance(a, list) True >>> isinstance(b, Animal) True >>> isinstance(c, Dog) True
在继承关系中,如果一个实例的数据类型是某个子类,那它的数据类型也可以被看做是父类。但是,反过来就不行:
>>> b = Animal() >>> isinstance(b, Dog) False
多态的好处就是,当我们需要传入
Dog
、Cat
、Tortoise
……时,我们只需要接收Animal
类型就可以了,因为Dog
、Cat
、Tortoise
……都是Animal
类型,然后,按照Animal
类型进行操作即可。由于Animal
类型有run()
方法,因此,传入的任意类型,只要是Animal
类或者子类,就会自动调用实际类型的run()
方法,这就是多态的意思:
对于一个变量,我们只需要知道它是Animal
类型,无需确切地知道它的子类型,就可以放心地调用run()
方法,而具体调用的run()
方法是作用在Animal
、Dog
、Cat
还是Tortoise
对象上,由运行时该对象的确切类型决定,这就是多态真正的威力:调用方只管调用,不管细节,而当我们新增一种Animal
的子类时,只要确保run()
方法编写正确,不用管原来的代码是如何调用的。这就是著名的“开闭”原则:对扩展开放:允许新增
Animal
子类;对修改封闭:不需要修改依赖
Animal
类型的run_twice()
等函数。
继承还可以一级一级地继承下来,就好比从爷爷到爸爸、再到儿子这样的关系。而任何类,最终都可以追溯到根类object,这些继承关系看上去就像一颗倒着的树。比如如下的继承树:
- 当我们定义一个class的时候,我们实际上就定义了一种数据类型(可见通过class可以定义很多种数据类型)。我们定义的数据类型和Python自带的数据类型,比如str、list、dict没什么两样:
-
静态语言 vs 动态语言
对于静态语言(例如Java)来说,如果需要传入
Animal
类型,则传入的对象必须是Animal
类型或者它的子类(他的子类依然可以看作是Animal类),否则,将无法调用run()
方法,因为Java定义函数需要提前声明数据或变量类型,数据类型对不上函数当然无法执行,这就是静态语言的特性。对于Python这样的动态语言来说,则不一定需要传入
Animal
类型(可以是Sun类,可以是Sea类等等)(因为python不需要你声明参数或数据类型,他的适应性很强)。我们只需要保证传入的对象有一个run()
方法就可以了:class Timer(object): def run(self): print('Start...')
这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子(症结所在:python不限定传入的数据类型)。
补充关于鸭子类型的概念:
首先要明确python里“鸭子类型”的概念:
1、看起来像鸭子(举例:一个纸做的手工,参考了鸭子的外形)
2、走起路来像鸭子(这个手工作品,实现了八字走路,而且内置了扬声器可以嘎嘎叫)
总结:那么我们可以认为这个纸工艺品,它就是鸭子。
这就是python的灵活之处,不拘泥于静态类型的严格定义,只要这个类型内部有run()函数,可以看作是目标类型。(再做个补充,其实不管是timer类也好,还是其他什么类也好,只要有run()函数,都可以传入到run_twice里运行,因为他们满足run_twice里需要运行run()函数的需要)
郑重声明:以上内容是基于 廖雪峰的python教程 整理的,不是原创,不喜勿喷。