## 类的继承
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过继承机制。
通过继承创建的新类称为**子类**或**派生类**,被继承的类称为**基类**、**父类**或**超类**。
**继承语法**
~~~
class 派生类名(基类名)
...
~~~
在python中继承中的一些特点:
* 1、如果在子类中需要父类的构造方法就需要显式的调用父类的构造方法,或者不重写父类的构造方法.。
* 2、在调用基类的方法时,需要加上基类的类名前缀,且需要带上 self 参数变量。区别在于类中调用普通函数时并不需要带上 self 参数
* 3、Python 总是首先查找对应类型的方法,如果它不能在派生类中找到对应的方法,它才开始到基类中逐个查找。(先在本类中查找调用的方法,找不到才去基类中找)。
如果在继承元组中列了一个以上的类,那么它就被称作"多重继承" 。
**语法:**
派生类的声明,与他们的父类类似,继承的基类列表跟在类名之后,如下所示:
~~~
class SubClassName (ParentClass1[, ParentClass2, ...]):
...
~~~
## 实例
```
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Parent: # 定义父类
parentAttr = 100
def __init__(self):
print "调用父类构造函数"
def parentMethod(self):
print '调用父类方法'
def setAttr(self, attr):
Parent.parentAttr = attr
def getAttr(self):
print "父类属性 :", Parent.parentAttr
class Child(Parent): # 定义子类
def __init__(self):
print "调用子类构造方法"
def childMethod(self):
print '调用子类方法'
c = Child() # 实例化子类
c.childMethod() # 调用子类的方法
c.parentMethod() # 调用父类方法
c.setAttr(200) # 再次调用父类的方法 - 设置属性值
c.getAttr() # 再次调用父类的方法 - 获取属性值
```
以上代码执行结果如下:
~~~
调用子类构造方法
调用子类方法
调用父类方法
父类属性 : 200
~~~
你可以继承多个类
~~~
class A: # 定义类 A
.....
class B: # 定义类 B
.....
class C(A, B): # 继承类 A 和 B
.....
~~~
你可以使用issubclass()或者isinstance()方法来检测。
* issubclass() - 布尔函数判断一个类是另一个类的子类或者子孙类,语法:issubclass(sub,sup)
* isinstance(obj, Class) 布尔函数如果obj是Class类的实例对象或者是一个Class子类的实例对象则返回true
## Python 子类继承父类构造函数说明
如果在子类中需要父类的构造方法就需要显式地调用父类的构造方法,或者不重写父类的构造方法。
子类不重写\_\_init\_\_,实例化子类时,会自动调用父类定义的\_\_init\_\_。
## 实例
```
class Father(object):
def __init__(self, name):
self.name=name
print ( "name: %s" %( self.name) )
def getName(self):
return 'Father ' + self.name
class Son(Father):
def getName(self):
return 'Son '+self.name
if __name__=='__main__':
son=Son('yingtai')
print ( son.getName() )
```
输出结果为:
~~~
name: yingtai
Son yingtai
~~~
如果重写了\_\_init\_\_时,实例化子类,就不会调用父类已经定义的\_\_init\_\_,语法格式如下:
## 实例
```
class Father(object):
def __init__(self, name):
self.name=name
print ( "name: %s" %( self.name) )
def getName(self):
return 'Father ' + self.name
class Son(Father):
def __init__(self, name):
print ( "hi" )
self.name = name
def getName(self):
return 'Son '+self.name
if __name__=='__main__':
son=Son('yingtai')
print ( son.getName() )
```
输出结果为:
~~~
hi
Son yingtai
~~~
如果重写了\_\_init\_\_时,要继承父类的构造方法,可以使用super关键字:
~~~
super(子类,self).__init__(参数1,参数2,....)
~~~
还有一种经典写法:
```
父类名称.__init__(self,参数1,参数2,...)
```
## 实例
```
class Father(object):
def __init__(self, name):
self.name=name
print ( "name: %s" %( self.name))
def getName(self):
return 'Father ' + self.name
class Son(Father):
def __init__(self, name):
super(Son, self).__init__(name)
print ("hi")
self.name = name
def getName(self):
return 'Son '+self.name
if __name__=='__main__':
son=Son('yingtai')
print ( son.getName() )
```
输出结果为:
~~~
name: yingtai
hi
Son yingtai
~~~
## 方法重写
如果你的父类方法的功能不能满足你的需求,你可以在子类重写你父类的方法:
实例:
```
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Parent: # 定义父类
def myMethod(self):
print '调用父类方法'
class Child(Parent): # 定义子类
def myMethod(self):
print '调用子类方法'
c = Child() # 子类实例
c.myMethod() # 子类调用重写方法
```
执行以上代码输出结果如下:
~~~
调用子类方法
~~~
## 基础重载方法
下表列出了一些通用的功能,你可以在自己的类重写:
![](https://img.kancloud.cn/76/f8/76f8df4d71d7f19687cbf9876d72fdbe_835x491.png)
## 运算符重载
Python同样支持运算符重载,
__add__(self,rhs) self + rhs 加法
__sub__(self,rhs) self - rhs 减法
__mul__(self,rhs) self * rhs 乘法
__truediv__(self,rhs) self / rhs 除法
__floordiv__(self,rhs) self //rhs 地板除
__mod__(self,rhs) self % rhs 取模(求余)
__pow__(self,rhs) self **rhs 幂运算
实例如下:
```
#!/usr/bin/python
class Vector:
def __init__(self, a, b):
self.a = a
self.b = b
def __str__(self):
return 'Vector (%d, %d)' % (self.a, self.b)
def __add__(self,other):
return Vector(self.a + other.a, self.b + other.b)
v1 = Vector(2,10)
v2 = Vector(5,-2)
print v1 + v2
```
以上代码执行结果如下所示:
~~~
Vector(7,8)
~~~
## 类属性与方法
### 类的私有属性
**\_\_private\_attrs**:两个下划线开头,声明该属性为私有,不能在类的外部被使用或直接访问。在类内部的方法中使用时**self.\_\_private\_attrs**。
### 类的方法
在类的内部,使用def关键字可以为类定义一个方法,与一般函数定义不同,类方法必须包含参数 self,且为第一个参数
### 类的私有方法
**\_\_private\_method**:两个下划线开头,声明该方法为私有方法,不能在类的外部调用。在类的内部调用**self.\_\_private\_methods**
## 实例
```
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class JustCounter:
__secretCount = 0 # 私有变量
publicCount = 0 # 公开变量
def count(self):
self.__secretCount += 1
self.publicCount += 1
print self.__secretCount
counter = JustCounter()
counter.count()
counter.count()
print counter.publicCount
print counter.__secretCount # 报错,实例不能访问私有变量
```
Python 通过改变名称来包含类名:
~~~
1
2
2
Traceback (most recent call last):
File "test.py", line 17, in <module>
print counter.__secretCount # 报错,实例不能访问私有变量
AttributeError: JustCounter instance has no attribute '__secretCount'
~~~
Python不允许实例化的类访问私有数据,但你可以使用object.\_className\_\_attrName(**对象名.\_类名\_\_私有属性名**)访问属性,参考以下实例:
```
#!/usr/bin/python
# -*- coding: UTF-8 -*-
class Yingtai:
__site = "www.yingtai.com"
yingtai= Yingtai()
print yingtai._Yingtai__site
```
执行以上代码,执行结果如下:
~~~
www.yingtai.com
~~~
### 单下划线、双下划线、头尾双下划线说明:
* **\_\_foo\_\_**: 定义的是特殊方法,一般是系统定义名字 ,类似\_\_init\_\_()之类的。
* **\_foo**: 以单下划线开头的表示的是 protected 类型的变量,即保护类型只能允许其本身与子类进行访问,不能用于from module import \*
* **\_\_foo**: 双下划线的表示的是私有类型(private)的变量, 只能是允许这个类本身进行访问了。