继承
- 什么是继承?
继承是一种创建新的类的方式,新创建的叫子类,继承的叫父类、超类、基类。 - 特点:子类可以使用父类的属性(特征、技能)
- 继承是类与类之间的关系
- 为什么要继承?
减少代码冗余、提高重用性 - 可以用 isinstance() 或 issubclass() 验证实例或类的从属关系
# 继承
# 1.让类之间产生关系,从而实现了多态
# 2.提高了代码复用性
# 3.在创建类的时候,如果省略了父类,则默认父类为object
# 4.object时所有类的父类
class Animal:
def sleep(self):
print('动物会睡觉')
def run(self):
print('动物会跑')
# class Dog:
#
# def sleep(self):
# print('狗会睡觉')
#
# def run(self):
# print('狗会跑')
#
# def speak(self):
# print('狗会旺旺')
# 想定义一个狗类
# 第一个思路:直接改Animals类,添加狗独有的功能
# 这样修改很麻烦,会破坏了OCP原则
# 第二个思路:创建一个新的狗类
# 会出现大量的复制粘贴,修改起来也比较繁琐
# 第三个类,利用类的继承
# 在定义类的时候可以在类名后的括号中指定当前类的父类(超类,基类)
class Dog(Animal):
def speak(self):
print('狗会旺旺')
def run(self):
print('狗会跑')
d = Dog()
d.sleep()
d.run()
d.speak()
# d既时Dog的实例也是Animals的实例
# 检查一个实例是不是某个类的实例
r = isinstance(d,Dog)
print(r)
r = isinstance(d,Animal)
print(r)
# 检查某个类是不是另一个类的子类
r = issubclass(Dog,Animal)
print(r)
# 检查object是否为任意类的父类
r = issubclass(Animal,object)
print(r)
r = issubclass(Dog,object)
print(r)
r = issubclass(int,object)
print(r)
# 如果子类和父类出现同名方法,则先找子类,子类没有再找父类
d.run()
方法的重写
- 如果子类和父类出现同名方法,则先找子类,子类有则调用子类方法
- 如果子类没有,再找父类,调用父类方法
class A(object):
def test(self):
print('A...')
class B(A):
def test(self):
print('B...')
class C(B):
pass
c = C()
c.test()
super()
- super()用来动态获取当前父类
- 可以用来避免子类属性覆盖父类属性
- 子类中只定义独有属性即可
- super()不需要传递self
class Animal:
def __init__(self,name):
self.name = name
def sleep(self):
print('动物会睡觉')
def run(self):
print('动物会跑')
@property
def name(self):
return self._name
@name.setter
def name(self,name):
self._name = name
# 子类有而父类没有的内容,可以添加进来
# 但是要避免把父类的属性给覆盖掉
class Dog(Animal):
def __init__(self,name,age):
# self._name = name
# 希望调用父类的__init__
# Animal.__init__(self,name)
# 但是最好不要把父类写死
# super可以用来获取当前类的父类
# super()初始化父类,不需要传递self
super().__init__(name)
# 子类独有的属性再自己写
self._age = age
def sleep(self):
print('狗会睡觉')
def run(self):
print('狗会跑')
def speak(self):
print('狗会旺旺')
@property
def age(self):
return self._age
@age.setter
def age(self,age):
self._age = age
d = Dog('大狼狗',6)
print(d.name,d.age)
多重继承
- Python中时可以多继承的,我们可以为一个类指定多个父类
- 两个父类之间不能有继承关系
- 类名.bases 可以获取当前类的所有父类
- 注意: 尽量少使用多重继承
class A(object):
def test1(self):
print('A...')
class B(object):
def test1(self):
print('B中tetest1')
def test2(self):
print('B...')
class C(A,B):
pass
# 类名.__bases__ 可以获取当前类的所有父类
print(C.__bases__)
c = C()
# 当父类中有同名的方法,则按照继承的顺序进行寻找
# 即如果改成class C(B,A): 则调用的结果会不同
c.test1()
c.test2()
多态
- 多态是面向对象三大特性之一
- 一个对象也是可以有不同的形态取呈现
- 一个函数可以处理多个对象就是多态的一种体现
- 体现了函数的灵活性
- 对扩展开放(Open for extension):允许子类重写方法函数
- 对修改封闭(Closed for modification):不重写,直接继承父类方法函数
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
@property
def name(self):
return self._name
@name.setter
def name(self, name):
self._name = name
class C:
pass
a = A('葫芦娃')
b = B('钢铁侠')
# a其实是一个__main__.A object
print(a)
# 输出了字符串,没有property之前其实是a.name()
print(a.name)
# 定义一个函数
def speak(obj):
print('好好复习%s'%obj.name)
# 传入给speak()函数的对象a实际上是__main__.A object,用字符串格式化依然可以进行a.name的传入
# 这说明了函数的灵活性,函数的对象可以是多种类型,并不局限于字符串等常见格式
speak(a)
# speak2这个函数违反了多态
# 只能处理一个类型的对象,函数适用性差
def speak2(obj):
if isinstance(obj,A):
print('好好复习%s'%obj.name)
else:
print('不是speak2()想要的对象')
speak2(a)
speak2(b)
属性和方法
- 类属性: 直接在类中定义的属性
- 类属性可以通过类和该类的实例进行访问
- 类中的属性只能通过类对象进行修改,无法通过实例对象来修改
- 修改类中属性相当于修改默认值,不会影响创建过的实例对象的属性,但是会影响新创建的实例对象的属性
- 实例对象先找自己的实例属性,没有了才找类属性
- 以self为第一个参数的方法都是实例方法
- 代码示例:
class A(object):
count = 0
def __init__(self):
# 这个反而是实例属性
self.name = '葫芦娃'
# print(A.count)
#
a = A()
# print(a.count)
# a.count = 10
# print('A:',A.count)
# print('a:',a.count)
# A.count = 20
# print('A:',A.count)
# print('a:',a.count)
# self是实例属性
print('a', a.name)
# AttributeError: type object 'A' has no attribute 'name'
# print('A',A.name)
- 类方法: 在类的内部使用@classmethod来修饰的方法属于类方法
- 首先形式上的区别,实例方法隐含的参数为类实例self,而类方法隐含的参数为类本身cls。 静态方法无隐含参数,主要为了类实例也可以直接调用静态方法。
- 逻辑上,类方法被类调用,实例方法被实例调用,静态方法两者都能调用。主要区别在于参数传递上的区别,实例方法悄悄传递的是self引用作为参数,而类方法悄悄传递的是cls引用作为参数。
- 注意:
- 当通过实例对象调用函数可以自动传入self
- 当通过类对象调用函数不会自动传入self,需要手动添加实例对象名, 但通过@classmethod装饰的方法可以不用传入实例名
- 静态方法: 在类中以@staticmethod修饰的方法
- 静态方法不用传入参数
- 静态方法可以通过类调用也可以通过实例调用
# !/usr/bin/python
# Filename: 模块.py
# Data : 2020/06/17
# Author : --king--
# ctrl+alt+L自动加空格格式化
class A(object):
# 类属性: 直接在类中定义的属性
# 类属性可以通过类和该类的实例进行访问
count = 0
def __init__(self):
# 这个反而是实例属性
self.name = '葫芦娃'
def text(self):
print('这是self方法:',self)
# 类方法: 在类的内部使用@classmethod来修饰的方法属于类方法
@classmethod
def text2(cls):# cls就代表类名和self一样自动传入
print('这是test2方法:',cls)
print(cls.count)
# 静态方法:再累内部使用@staticmethod来修饰的方法
@staticmethod
def text3():
print('这是text3方法')
a = A()
# 类方法可以通过类对象和实例对象调用
A.text2()
a.text2()
# 静态方法可以不传入函数直接调用
# 他本身与类无关,只是用来保存一个功能函数
A.text3()
a.text3()