一、继承的简介
1.提高了代码的复用性
2.让类与类之间产生了关系,有了这个关系,才有了多态继承,是面向对象的三大特征之一
class Person():
name = ''
age = ''
class Doctor():
name = ''
age = ''
def study(self):
print('治病救人')
class Sldie():
name = ''
age = ''
def study(self):
print('保家卫国')
举例:
定义一个狗类
1.直接修改动物类-修改起来比较麻烦,会违反ocp原则
2.直接创建一个新类(狗)-这样比较麻烦,会出现大量重复性代码,因为使用了大量的复制粘贴
3.直接从Animal类中继承他的属性和方法
#定义一个动物类
class Animal:
def run(self):
print('动物跑..。。')
def sleep(self):
print('动物睡觉.。。')
a = Animal()
a.run() #动物跑..。。
# # 定义类时,可以在类名后面加上括号,括号中指定的是当前类的父类(超类,基类,super)
class Dog(Animal):
def run(self):
print('狗跑..。。')
#
# def sleep(self):
# print('狗睡觉.。。')
#
def home(self):
print('狗看家.。。')
pass
d = Dog()
# print(d) #<__main__.Dog object at 0x000001A6BE4F4148>
#
d.run() #狗跑..。。
# d.sleep() #动物睡觉.。。
r = isinstance(d,Dog)
print(r) #True
s = isinstance(d,Animal)
print(s) #True
若創建类的时候省略了父类,则默认父类是object
object是所有类的父类,所有类都继承了object
class Person():
pass
# issubclass()--检查一个类是不是另一个类的子类
print(issubclass(Dog,Animal)) #True
print(issubclass(Dog,object)) #True
print(issubclass(Animal,object)) #True
print(issubclass(Person,object)) #True
二、方法的重写
若在子类中有和父类同名的方法,通过子类的实例去调用方法时,会调用子类的方法,而非父类的方法
这就是方法的重写(覆盖)
当我们去调用一个对象的时候
会优先调用当前对象的方法,若当前对象中没有这个方法,则会去父类中寻找,若其父类中
也没有,则会去父类的父类寻找,若无,则会逐级向上,直到object中去,若object也没有,会报错
class A(object):
def test(self):
print('A....')
class B(A):
def test(self):
print('B....')
class C(B):
def test(self):
print('C....')
c=C()
c.test() #C....
c.sty() #AttributeError: 'C' object has no attribute 'sty'
三、super()
父类中所有的方法都会被子类继承,包括特殊方法
#定义一个动物类
class Animal:
def __init__(self,name):
self._name = name
def run(self):
print('动物跑..。。')
def sleep(self):
print('动物睡觉.。。')
@property
def name(self):
# print('property执行')
return self._name
@name.setter
def name(self,name):
self._name = name
# 希望能够直接调用父类的__init__来初始化父类中的属性
# super可以用了获取当前的父类
# 并且通过super()返回的对象,调用父类方法时不需要写self
class Dog(Animal):
def __init__(self,name,age):
# 希望能够直接调用父类的__init__
# self._name = name
# Animal.__init__(self,name)
super().__init__(name)
self._age = age
def run(self):
print('狗跑..。。')
#
# def sleep(self):
# print('狗睡觉.。。')
#
def home(self):
print('狗看家.。。')
@property
def age(self):
# print('property执行')
return self._age
@age.setter
def age(self, age):
self._age = age
# e = Dog() #TypeError: __init__() missing 1 required positional argument: 'name'
#子类未重写init方法之前,即注释方法def __init__(self,name,age):
# e = Dog('蛇精病')
# print(e.name) #蛇精病
# e.name = '二哈'
# print(e.name) #二哈
#子类未重写init方法之后
e = Dog('long',3)
print(e.name,e.age) #long 3
四、多重继承
语法:类名.__bases__可以用了获取当前类的所有父类
在Python中是支持多重继承的,也就是我们可以为一个类同时指定多个父类
在开发中没有特殊情况,尽量避免使用多重继承,因为多重继承会让我们代码过于复杂
如果多个父类中有同名的方法,则会在第一个父类中寻找,然后找第二个…(父类顺序以写入的顺序为准)
前边会覆盖后面的
class A(object):
def test(self):
print('A....')
class B(object):
def test2(self):
print('B....')
class C(A,B):
pass
print(C.__bases__) #(<class '__main__.A'>, <class '__main__.B'>)-元组
print(A.__bases__) #(<class 'object'>,)-元组
print(B.__base__) #<class 'object'>
c = C()
c.test() #A....
c.test2() #B....
五、多态
面向对象的三大特征之一
熊(黑熊、棕熊、北极熊…)
一个对象可以以不同的形态去呈现
# 定义一个类
class A:
def __init__(self,name):
self._name = name
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
class B:
def __init__(self,name):
self._name = name
# def __len__(self):
#
# return 5
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
class C:
pass
# 定义一个函数
def speak(obj):
print('你好 %s'%obj.name)
# 在speak2这个函数中做了一个类型检查,也就是只有obj是A类型的对象的时候,才可以正常使用,其他类型的对象无法使用该函数,这个函数其实就违反了多态
# 违反了多态的函数,只适用于一种类型的对象,无法处理其他类型的对象,这样导致函数的适用性非常差
def speak2(obj):
# 类型检查
if isinstance(obj, A):
print('你好 %s' % obj.name)
a = A('葫芦娃')
b = B('钢铁侠')
# print(len(b)) #TypeError: object of type 'B' has no len()
c = C()
speak(b) #你好 钢铁侠
speak2(a) ##你好 葫芦娃
speak2(b) #因为speak2中设置了对象的检查,只有A类型的可以输出,所以此时没有输出
# len()
lst = [1,2,3]
s = 'python'
print(len(lst)) #3
print(len(s)) #6
# 刚才用len()函数来检查不同对象类型的长度其实就是面向对象的特征之一
# 之所有len()这个函数能获取长度,是因为这些对象中具有一个特殊方法__len__
# 换句话说只要对象中有__len__特殊方法,就可以通过len()方法来获取它的长度
# 面向对象的三大特征
# 封装 确保对象中的数据更安全
# 继承 保证了对象的可扩展性
# 多态 保证了程序的灵活性
# len()
lst = [1,2,3]
s = 'python'
print(len(lst)) #3
print(len(s)) #6
刚才用len()函数来检查不同对象类型的长度其实就是面向对象的特征之一
之所以len()这个函数能获取长度,是因为这些对象中具有一个特殊方法__len__
换句话说只要对象中有__len__特殊方法,就可以通过len()方法来获取它的长度
六、 类中的属性和方法
类属性:
实例属性
类方法:
实例方法
静态方法
class A(object):
# 类属性 直接在类中定义的属性就是类属性
# 类属性可以通过类或类的实例访问到
# 类属性只能通过类对象来修改,无法通过实例对象来修改
count = 0
def __init__(self):
# 实例属性,通过实例对象添加的属性属于实例属性
# 实例属性只能通过实例属性来访问和修改,类对象无法访问和修改
self.name = '葫芦娃'
# 实例方法
# 在类中定义,以self为第一个参数都是实例方法
# 实例方法在调用时,Python会将调用对象作为self传入
# 通过类对象调用时,不会自动传self,必须手动传self
def test(self):
print('我是test方法')
# 类方法
# 类方法的第一个参数是cls,也会被自动传递,cls就是当前的类对象
# 类方法可以通过类去调用,也可以通过实例调用
@classmethod
def test2(cls):
print('我是test2方法.........',cls)
print(cls.count)
# 静态方法
# 静态方法,基本上是一个和当前类无关的方法,它只是一个保存到当前类中的函数
# 静态方法一般都是些工具方法,和当前类无关
@staticmethod
def test3():
print('我是test3方法........')
a = A()
# 实例属性 通过实例对象添加的属性属于实例属性
a.count = 5
print('A ',A.count) # A 0
print('a ',a.count) # a 5
A.count = 8
print('A ',A.count) # A 8
print('a ',a.count) # a 5
print('a ',a.name) # a 葫芦娃
# print('A ',A.name) # AttributeError: type object 'A' has no attribute 'name'
a.test() # 实例对象在调用--我是test方法
# A.test() # TypeError: test() missing 1 required positional argument: 'self'
A.test(2) #类对象在调用-我是test方法
# a.test() 等价于 A.test(a)
A.test2() #我是test2方法......... <class '__main__.A'> 8
a.test2() #我是test2方法......... <class '__main__.A'> 8
# A.test2() 等价于 a.test2()
A.test3() #我是test3方法........
a.test3() #我是test3方法........
# 类属性
# 实例属性
# 类方法
# 实例方法
# 静态方法