概括

Python中面向对象编程有三大特性:封装、继承和多态。
封装: 函数是对语句的封装;类是对函数和变量的封装。
继承: 类和类之间可以人为手动的建立父子关系,父类的属性和方法,子类可以使用。
多态: 是一种编程技巧,提高代码的灵活度。

1.封装

函数是对一个一个语句进行封装。

def test():
    x = 18  # 赋值语句
    x += 2  # 算数运算符表达式语句
    print('hello world')

类是对函数和变量的封装

class Person(object):
    type = '人类'

    def __init__(self):
        pass

    def play_game(self):
        pass

2.继承

继承是面向对象软件设计中的一个概念,描述的是多个类之间的所属关系,可以使子类具有分类的属性和方法,或者重新定义,追加属性和方法等。
例如一个A类的属性和方法可以复用,B类继承于A类,那么A类可称为基类,亦可叫做父类,B类则被称为派生类,亦可叫做子类。

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def sleep(self):
        print(self.name + '正在睡觉')

class Student(Person):
    def study(self):
        print(self.name + '正在看书')
# 调用 __init__ 方法,Student类没有实现,会自动找 Person 父类
s1 = Student('张三', 18)
print(s1.name)  #张三  父类里定义的属性,子类可以直接使用
s1.sleep()  #张三正在睡觉  父类的方法子类实例对象可以直接调用
s1.study()  #张三正在看书

多继承
子类可以有多个父类,继承所有父类的属性和方法。
语法格式:

class 子类名(父类名1,父类名2...)
    pass
class A(object):
    def test1(self):
        print('我是test1')
    def demo(self):
        print('我是A类里的demo方法')
        
class B(object):
    def test2(self):
        print('我是test2')
    def demo(self):
        print('我是B类里的demo方法')

class C(A, B):
    pass

c = C()
c.test1()  
c.test2()  
# 如果两个不同的父类有同名方法,可以使用__mro__属性可以查看方法的调用顺序
c.demo()   
print(C.__mro__)

运行结果:

我是test1
我是test2
我是A类里的demo方法
(<class ‘main.C’>, <class ‘main.A’>, <class ‘main.B’>, <class ‘object’>)

私有属性的继承特点

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        self.__score = 90

    def sleep(self):
        print(self.name + '正在睡觉')

    def __test(self):
        print('我是Person类里的test方法')

class Student(Person):
    def __demo(self):
        print('我是Student里的demo方法')
        
p = Student('源', 18)
print(p.name)
p.sleep()
p._Student__demo()  # 自己类里定义的私有方法   对象名._类名__私有方法名()
p._Person__test()  # 可以通过 对象名._父类名__私有方法调用()
print(p._Person__score)

运行结果:


源正在睡觉
我是Student里的demo方法
我是Person类里的test方法
90

私有属性和方法,子类不会继承
所以 p._Student__test() ,print(p._Student__score),会报错。

新式类与经典类
新式类:继承自object的类,我们称之为新式类
经典类:不继承自object的类
在python2里,如果不手动的指定一个类的父类是object,这个类就是一个经典类
在python3里不存在经典类,都是新式类。
使用dir函数可以查看object类提供的一些内置属性和方法。

class Student:
    pass
s = Student()
print(dir(s))

对象相关的运算符和内置函数
身份运算符用来比较两个对象的内存地址,查看这两个对象是否是同一个对象。

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
class Teacher(object):
    pass

class Student(Person, Teacher):
    pass
    
p1 = Person('源', 18)
p2 = Person('源', 18)
print(p1 is p2)  # False,两个对象的内存地址不一样

type内置函数用来获取类对象

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age
        
class Teacher(object):
    pass

class Student(Person, Teacher):
    pass
    
p1 = Person('源', 18)
s = Student('张三', 20)
print(type(p1) == Person)  # True
print(type(s) == Person)   # False

isinstance内置函数用来判断一个对象是否是由指定的类(或者父类)实例化出来的

print(isinstance(s, (Student, Teacher)))  # True
print(isinstance(s, Person))  # True
print(isinstance(p1, Person))  # True
print(isinstance(p1, Student))  # False

issubclass 内置函数用来判断一个类是否是另一个类的子

print(issubclass(Student, (Person, Teacher)))  # True
print(issubclass(Person, Student))  # False

子类重写父类方法

class Person(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def eat(self):
        print(self.name + '正在吃东西')

class Student(Person):
    def __init__(self, name, age, score):
        # 子类在父类实现的基础上,又添加了自己新的功能
        # 调用父类方法的两种方式:
        # 1. 父类名.方法名(self,参数列表)
        # Person.__init__(self, name, age)
        # 2. 使用super直接调用父类的方法。推荐使用第二种方式
        super(Student, self).__init__(name, age)
        self.score = score

    def eat(self):
        print(self.name + '在课间休息时吃东西')

s = Student('源', 18, 90)  # 调用了父类的 __init__ 方法
s.eat()  
print(Student.__mro__)

运行结果:

源在课间休息时吃东西
(<class ‘main.Student’>, <class ‘main.Person’>, <class ‘object’>)

1.子类的实现和父类的实现完全不一样,子类可以选择重写父类的方法。
2.子类在父类的基础上又有更多的实现

3.多态

多态是基于继承,通过子类重写父类的方法,达到不同的子类对象调用相同的父类方法,得到不同的结果,提高代码的灵活度。
不使用多态时:

class PoliceDog(object):
    def attack_enemy(self):
        print('警犬正在攻击坏人')
        
class BlindDog(object):
    def lead_road(self):
        print('导盲犬正在领路')
        
class DrugDog(object):
    def search_drug(self):
        print('缉毒犬正在搜毒')
        
class Person(object):
    def __init__(self, name):
        self.name = name
        self.dog = None
    def work_with_pd(self):
        if self.dog is not None:
            self.dog.attack_enemy()
    def work_with_bd(self):
        if self.dog is not None:
            self.dog.lead_road()
    def work_with_dd(self):
        if self.dog is not None:
            self.dog.search_drug()

p = Person('源')

pd = PoliceDog()
p.dog = pd
p.work_with_pd()

bd = BlindDog()
p.dog = bd
p.work_with_bd()

dd = DrugDog()
p.dog = dd
p.work_with_dd()

不使用多态时,若不断添加新的功能,每次都需要改动Person类的源码,使得程序的扩展性太差。

使用多态时:

class Dog(object):
    def work(self): # 父类提供统一的方法。
        print('狗正在工作')

class PoliceDog(Dog): # 继承Dog
    def work(self):   # 子类重写方法,并且处理自己的行为
        print('警犬正在攻击敌人')

class BlindDog(Dog):
    def work(self):
        print('导盲犬正在领路')

class DrugDog(Dog):
    def work(self):
        print('缉毒犬正在搜毒')

class Person(object):
    def __init__(self, name):
        self.name = name
        self.dog = None
    def work_with_dog(self):
        if self.dog is not None and isinstance(self.dog, Dog):
            self.dog.work() # 根据对象的不同而产生不同的运行效果, 保障了代码的稳定性

p = Person('源')

pd = PoliceDog()
p.dog = pd
p.work_with_dog()

bd = BlindDog()
p.dog = bd
p.work_with_dog()

dd = DrugDog()
p.dog = dd
p.work_with_dog()

运行结果:

警犬正在攻击坏人
导盲犬正在领路
缉毒犬正在搜毒

使用多态时,同一个方法,只要是 Dog 的子类就可以传递,提供了代码的灵活性,并且传递不同对象,最终 work_with_dog 产生了不同的执行效果。