什么是类?
在python中,把具有相同属性和方法的对象归为一个类(class)。类是对象的模板或蓝图,类是对象的抽象化,对象是类的实例化。类不代表具体的事物,而对象表示具体的事物。
类的创建
class Foo: def bar(self): pass
第一行定义了类名:语法是class 后面紧接着类的名字,这样来定义一个类。(Ps:类的名字,首字母,有一个不可文的规定,最好是大写,这样需要在代码中识别区分每个类。)
第二行开始是类的方法,大家看到了,和函数非常相似,但是与普通函数不同的是,它的内部有一个“self”,参数,它的作用是对于对象自身的引用。
类的特点
- 类对象是多态的:也就是多种形态,这意味着我们可以对不同的类对象使用同样的操作方法,而不需要额外写代码。
- 类的封装:封装之后,可以直接调用类的对象,来操作内部的一些类方法,不需要让使用者看到代码工作的细节。
- 类的继承:类可以从其它类或者元类中继承它们的方法,直接使用。
1. 类的封装
对象里封装的是一些属性,而对象的方法封装在原类里,因此,当需要在其他脚本或模块中,利用其他脚本或模块的对象时,需要先导入原模块或者类。比如我在脚本(1)中定义了A对象,并且通过pickle的方式存储到文件中,当在脚本(2)需要通过pickle载入文件时,需要先import 脚本1中的类,否则会提示找不到原类。
类的封装可以封装类的属性和类的方法,也可以在对象中封装对象。比如:
class Foo: def __init__(self, name, age): #将name和age属性,封装到类中 self.name = name self.age = age def speak(self, word): # 将speak方法封装到类中 print("%s say %s" % (self.name, word)) F = Foo(name='诸葛亮', age=18) F.speak('hello') out: 诸葛亮 say hello
上边的__init__和self是什么鬼?
self是Python的类在实例化的时候,自动传值的东西,代表对象本身。多个对象,则self会在不同对象调用的时候,代表不同对象。
而__init__是类的构造方法,在类进行实例化的时候会自动执行。
2. 类的继承
类的继承就是可以从其他类中继承其他类的方法来使用。
class Human: def __init__(self): self.sex = ['man', 'woman'] def eat(self): print("Human can eat, for example: %s" % self.name) class Man(Human): def __init__(self, name, age): #将name和age属性,封装到类中 self.name = name self.age = age def speak(self, word): # 将speak方法封装到类中 print("%s say %s" % (self.name, word)) F = Man(name='诸葛亮', age=18) F.eat() # 调用了父类的eat方法 out:
Human can eat, for example: 诸葛亮
其中Man类是Human类的子类,也叫做派生类。
Human是Man类的父类,也叫做基类。
上边的代码实现了简单的继承,且继承关系简单,只有一个父类, 因此属于单继承。另外也有多继承,即从多个父类继承。
在使用多继承的时候, 子类调用父类的方法,如果多个父类无交集,会采用从下到上,从左到右的原则进行匹配。如果多个父类有交集,则采用从下到上, 直至交集前,然后从左到右进行匹配。这种方法叫做“广度优先”。
这里的从左到右是指,继承的先后, 比如Foo(Left, Right),那么Left类就是左,优先进行向上查找。
从下到上是指,从Foo类开始查找,然后查找Left类,然后查找Left类的父类直至交集前的最后一层父类。图示如下:
3. 类的多态
在Python用谈多态没有多大意义,多态的概念是应用于Java和C#这一类强类型语言中。在Java中,在类定义的时候,已经定义好了参数输入的类型,这与Python中是不同的。但是为了在Java中,支持Python中这样多种形态的参数输入形式,就有了多态的用法。它的实现是基于继承来实现的,用Python伪代码来表示如下:
class A: pass class B(A): pass class C(A): pass # 要求arg必须是A类型 def func(arg): pass #使用继承的话,就可以按照如下的方式使用 obj1 = B() obj2 = C() # 这样的话,obj1和obj2就可以作为多态参数输入 func(obj1) func(obj2)
4. Python2 类中的多继承
在上边已经介绍了Python3 中类的多继承为“广度优先”,那么在Python2中呢?
对于经典类,Python2中的继承为“深度优先”。
对于新式类,Python2中的继承为“广度优先”。
上边的两句话怎么理解呢?那么什么是新式类,什么是经典类?
其实很简单,新式类和经典类的区别,在书写的时候就能看出来,经典类:class A:.... ; 新式类: class A(object)。可以看出,二者区别就是创建的时候有没有继承自object.
如何用代码测试,请看如下代码
1 class A: 2 def f1(self): 3 print('A') 4 5 class B(A): 6 def f1(self): 7 print('B') 8 9 class C(A): 10 def f1(self): 11 print('C') 12 class D(B): 13 def f1(self): 14 print('D') 15 16 class E(C): 17 def f1(self): 18 print('E') 19 20 class F(D, E): 21 def f1(self): 22 print('F')
上边我定义了一种继承关系。测试步骤如下:
1. 创建F对象
obj = F()
2. 循序渐进调用对象方法
obj.f1()
每次调用obj.f1()都会打印出当前调用的是那个类中的f1方法。接下来修改对应类中的f1函数名,让f1方法在当前类中无法找到,这样就会触发子类去父类中去查找f1方法。多次尝试之后,可以得出如下的继承顺序图,从而验证了,经典类的多继承关系是深度优先!图示如下:
Python2 关于新式类的多继承关系,测试方法同上,最终结果表明:新式类的继承是“广度优先”。图示如下:
: