第 6 章 (2)面向对象进阶

简介

面向对象三大特征介绍

Python 是面向对象的语言,也支持面向对象编程的三大特性:继承、封装(隐藏)、多态。
1、封装(隐藏)
	隐藏对象的属性和实现细节,只对外提供必要的方法。相当于将“细节封装起来”,只对外
暴露“相关调用方法”。 
	通过前面学习的“私有属性、私有方法”的方式,实现“封装”。Python 追求简洁的 语法,
没有严格的语法级别的“访问控制符”,更多的是依靠程序员自觉实现。
2、继承
继承可以让子类具有父类的特性,提高了代码的重用性。 
从设计上是一种增量进化,原有父类设计不变的情况下,可以增加新的功能,或者改进已有的算法。
3、多态
	多态是指同一个方法调用,由于对象不同会产生不同的行为。生活中这样的例子比比
皆是:同样是休息方法,人不同休息方法不同。张三休息是睡觉,李四休息是玩游戏。

一、继承

	继承是面向对象程序设计的重要特征,也是实现“代码复用”的重要手段。 如果一个新类继承自
一个设计好的类,就直接具备了已有类的特征,就大大降低了工作 难度。已有的类,我们称为
“父类或者基类”,新的类,我们称为“子类或者派生类”。

1、语法格式

Python 支持多重继承,一个子类可以继承多个父类。继承的语法格式如下: 
		class 子类类名(父类 1[,父类 2,...]): 
			类体
	如果在类定义中没有指定父类,则默认父类是 object 类。也就是说,object 是所有类的父 类,
里面定义了一些所有类共有的默认实现,比如:__new__()。

注意:

定义子类时,必须在其构造函数中调用父类的构造函数。调用格式如下: 
	父类名.__init__(self, 参数列表)

示例代码:

class Person:

    def __init__(self, name, age):
        self.name = name
        self.__age = age

    def get_info(self):
        print('学生的信息:{0}的年龄是{1}岁'.format(self.name, self.__age))


class Student(Person):

    def __init__(self, name, age, score):
        self.score = score
        # 构造函数中包含调用父类构造函数。(根据需要,不是必须)
        # 子类并不会自动调用父类的__init__(),我们必须显式的调用它。
        Person.__init__(self, name, age)


s1 = Student('Jack', 14, 88)
s1.get_info()
print('s1对象内容:'dir(s1))
===================运行结果=========================
学生的信息:Jack的年龄是14岁
s1对象内容:['_Person__age', '__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
 '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', 
 '__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', 
 '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', 
 '__subclasshook__', '__weakref__', 'get_info', 'name', 'score']
===================运行结果=========================
# 我们可以看到子类‘Student’中拥有父类‘Person’的实例属性、方法等。

2、类成员的继承和重写

1. 成员继承:子类继承了父类除构造方法之外的所有成员。 
2. 方法重写:子类可以重新定义父类中的方法,这样就会覆盖父类的方法,也称为“重写”

示例代码:

class Person:

    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address

    def get_info(self):
        print('获得信息1:{0}的年龄是{1}岁!'.format(self.name, self.age))

    def country_info(self):
        print('国籍信息1:{0}来自{1}'.format(self.name, self.address))


class Student(Person):

    def __init__(self, name, age, address, score):
        self.score = score
        Person.__init__(self, name, age, address)  # 构造函数中包含调用父类构造函数

    def class_info(self):
        print('{0}是大一XX班的学生'.format(self.name))

    def get_info(self):   # 重写父类的方法
        print('获得信息2:{0}学生的成绩是{1}分!'.format(self.name, self.score))

    def country_info(self):   # 重写父类的方法
        print('国籍信息2:{0}是个留学生,来自{1}'.format(self.name, self.address))


s1 = Student('Jack', 20, '英国', 77)
s1.class_info()
s1.get_info()
s1.country_info()
# 查看类的继承层次结构:通过类的方法mro()或者类的属性__mro__可以输出这个类的继承层次结构。
print('Student类的继承层次结构:', Student.mro())
print('s1对象属性:', dir(s1))  # dir()查看对象属性
===================运行结果=========================
Jack是大一XX班的学生
获得信息2:Jack学生的成绩是77分!
国籍信息2:Jack是个留学生,来自英国
Student类的继承层次结构: [<class '__main__.Student'>, <class '__main__.Person'>, <class 'object'>]
s1对象属性:['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', 
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', 
'__init_subclass__', '__le__', '__lt__', '__module__', '__ne__', '__new__', 
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', 
'__subclasshook__', '__weakref__', 'address', 'age', 'class_info', 'country_info', 
'get_info', 'name', 'score']
===================运行结果=========================
# 注:object类是所有类的父类,因此所有的类都有object类的属性和方法。

3、重写__str__()方法

	object 有一个__str__()方法,用于返回一个对于“对象的描述”,对应于内置函数 str() 经常用于 
print()方法,帮助我们查看对象的信息。__str__()可以重写。

示例代码:

class Student:

    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        # 将对象转化成一个字符串,一般用于 print 方法
        return '{0}学生的年龄是{1}岁!'.format(self.name, self.age)


s1 = Student('Leo', 14)
print(s1)
===================运行结果=========================
Leo学生的年龄是14岁!
===================运行结果=========================

二、多重继承

	Python 支持多重继承,一个子类可以有多个“直接父类”。这样,就具备了“多个父 类”的特点。
但是由于,这样会被“类的整体层次”搞的异常复杂,尽量避免使用。

示例代码:

# 多重继承
class Animal:

    def __init__(self, name):
        self.name = name

    def run(self):
        print('{0}跑的快!'.format(self.name))

    def eat(self):
        print('{0}吃东西特别快!'.format(self.name))


class People:

    def __init__(self, name):
        self.name = name

    def learn(self):
        print('{0}学习算术!'.format(self.name))

    def eat(self):
        print('{0}吃东西比较慢!'.format(self.name))


class Dog1(Animal, People):

    def __init__(self, name):
        Animal.__init__(self,name)
        People.__init__(self,name)

    # def eat(self):
    #     print('{0}喜欢抓兔子吃!'.format(self.name))


class Dog2(People, Animal):

    def __init__(self, name):
        Animal.__init__(self,name)
        People.__init__(self,name)
        
	# def eat(self):
    #    print('{0}喜欢抓兔子吃!'.format(self.name))

dog1 = Dog1('Dog1')
dog1.run()
dog1.learn()
dog1.eat()
print('--------------华丽的分割线-----------------')
dog2 = Dog2('Dog2')
dog2.run()
dog2.learn()
dog2.eat()
# MRO()
# Python 支持多继承,如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将 
# “从左向右”按顺序搜索。 MRO(Method Resolution Order):方法解析顺序。 我们可以
# 通过 mro()方法获得 “类的层次结构”,方法解析顺序也是按照这个“类的层次结构”寻找的。
# 如果子类中也有重名的方法,首先会执行子类中的方法(此时的方法是方法的重写)。
print('Dog1 MRO:', Dog1.mro())
print('Dog2 MRO:', Dog2.mro())
===================运行结果=========================
Dog1跑的快!
Dog1学习算术!
Dog1吃东西特别快!
--------------华丽的分割线-----------------
Dog2跑的快!
Dog2学习算术!
Dog2吃东西比较慢!
Dog1 MRO: [<class '__main__.Dog1'>, <class '__main__.Animal'>, <class '__main__.People'>, <class 'object'>]
Dog2 MRO: [<class '__main__.Dog2'>, <class '__main__.People'>, <class '__main__.Animal'>, <class 'object'>]
===================运行结果=========================

1、super()获得父类定义

super()代表父类的定义,不是父类对象。

示例代码:

# super 测试
class Animal:

    def __init__(self, name):
        self.name = name

    def run(self):
        print('{0}跑的快!'.format(self.name))


class Dog(Animal):

    def __init__(self, name):
        Animal.__init__(self, name)

    def run(self):
        super().run() # 通过super调用父类的方法run()


dog = Dog('二哈')
dog.run()
===================运行结果=========================
二哈跑的快!
===================运行结果=========================

三、多态

多态(polymorphism)是指同一个方法调用由于对象不同可能会产生不同的行为。

关于多态要注意以下 2 点:

1. 多态是方法的多态,属性没有多态。 
2. 多态的存在有 2 个必要条件:继承、方法重写。

示例代码:

# 多态测试
class Animal:

    def shout(self):
        print('动物在黑夜中一直叫!')


class Dog(Animal):

    def shout(self):
        print('小狗汪汪叫!')


class Cat(Animal):

    def shout(self):
        print('小猫喵喵叫!')


def animal_shout(animal):

    if isinstance(animal, Animal):  # 传入的对象不同,shout方法对应的实际行为也不同。
        animal.shout()


dog = Dog()
cat = Cat()
animal_shout(dog)
animal_shout(cat)
===================运行结果=========================
小狗汪汪叫!
小猫喵喵叫!
===================运行结果=========================

四、特殊方法和运算符重载

常见的特殊方法统计如下:
在这里插入图片描述

每个运算符实际上都对应了相应的方法,统计如下:
在这里插入图片描述
在这里插入图片描述

五、特殊属性

Python 对象中包含了很多双下划线开始和结束的属性,这些是特殊属性,有特殊用法。

这里我们列出常见的特殊属性:
在这里插入图片描述

六、对象的浅拷贝和深拷贝

1、变量的赋值操作

只是形成两个变量,实际还是指向同一个对象。 

2、浅拷贝

Python拷贝一般都是浅拷贝。拷贝时,对象包含的子对象内容不拷贝。因此,源对象和拷贝对象会引用同一个子对象。 

3、深拷贝

使用 copy 模块的deepcopy函数,递归拷贝对象中包含的子对象。源对象和拷贝对象 所有的子对象也不同。

七、组合

	“is-a”关系,我们可以使用“继承”。从而实现子类拥有的父类的方法和属性。“is-a” 关系指的是
类似这样的关系:狗是动物,dog is animal。狗类就应该继承动物类。 
	“has-a”关系,我们可以使用“组合”,也能实现一个类拥有另一个类的方法和属性。” has-a”关
系指的是这样的关系:手机拥有 CPU。 MobilePhone has a CPU。

示例代码:

# 测试组合
class MobilePhone:

    def __init__(self, cpu, screen):
        self.cpu = cpu
        self.screen = screen


class CPU:

    def calculate(self):
        print('CPU具有运算功能。')


class Screen:

    def show(self):
        print('Screen可以显示一个好看的画面。')


cpu = CPU()
screen = Screen()
phone = MobilePhone(cpu, screen)

phone.cpu.calculate()
phone.screen.show()
===================运行结果=========================
CPU具有运算功能。
Screen可以显示一个好看的画面。
===================运行结果=========================

八、设计模式_工厂模式实现

	设计模式是面向对象语言特有的内容,是我们在面临某一类问题时候固定的做法,设计模式有很多种,
比较流行的是:GOF(Goup Of Four)23 种设计模式。
	对于初学者,我们学习两个最常用的模式:工厂模式和单例模式。 
	工厂模式实现了创建者和调用者的分离,使用专门的工厂类将选择实现类、创建对象进行统一的管理
和控制。

示例代码:

# 工厂模式
class Carfactory:

    def create_car(self, brand):
        if brand == 'BMW':
            return BMW()
        elif brand == 'BYD':
            return BYD()
        elif brand == 'BenC':
            return BenC()
        else:
            print('未知品牌的汽车!!!')


class BMW:

    def run(self):
        print('BMW车跑的快!')


class BYD:

    def run(self):
        print('BYD车跑的慢!')


class BenC:
    def run(self):
        print('BenC车跑的比较快!')


factory = Carfactory()
car1 = factory.create_car('BMW')
car1.run()
car2 = factory.create_car('BYD')
car2.run()
car3 = factory.create_car('QQ')
print('car1(BMW) obj:{0}'.format(car1))
print('car2(BYD) obj:{0}'.format(car2))
===================运行结果=========================
BMW车跑的快!
BYD车跑的慢!
未知品牌的汽车!!!
car1(BMW) obj:<__main__.BMW object at 0x0000022F7CA2FB38>
car2(BYD) obj:<__main__.BYD object at 0x0000022F7CA2FC88>
===================运行结果=========================

九、设计模式_单例模式实现

	单例模式(Singleton Pattern)的核心作用是确保一个类只有一个实例,并且提供一 个访问该实例
的全局访问点。 
	单例模式只生成一个实例对象,减少了对系统资源的开销。当一个对象的产生需要比较多的资源,
如读取配置文件、产生其他依赖对象时,可以产生一个“单例对象”,然后永久驻留内存中,从而极大
的降低开销。 

单例模式有多种实现的方式,我们这里推荐重写__new__()的方法。

示例代码:

# 测试单例模式
class MySingleton:

    __obj = None
    __init_flag = True

    def __new__(cls, *args, **kwargs):
        if cls.__obj == None:
            cls.__obj = object.__new__(cls)
        return cls.__obj

    def __init__(self, name):
        if MySingleton.__init_flag:
            print('init......')
            self.name = name
            MySingleton.__init_flag = False


a = MySingleton('aa')
print('a:', a)
b = MySingleton('bb')
print('b:', b)
===================运行结果=========================
init......
a: <__main__.MySingleton object at 0x000001D20F662C50>
b: <__main__.MySingleton object at 0x000001D20F662C50>
===================运行结果=========================
# 此时我们会发现a、b同属于一个对象,而且初始化只执行了一次。

上述联系的汽车工厂类(CarFactory)实现单利模式的示例代码:

# 工厂类(CarFactory)实现单利模式
class CarFactory:
    __obj = None
    __init_flag = True

    def __new__(cls, *args, **kwargs):
        if cls.__obj == None:
            cls.__obj = object.__new__(cls)
        return cls.__obj

    def __init__(self):
        if CarFactory.__init_flag:
            print('CarFactory init ......')
            CarFactory.__init_flag = False

    def creat_car(self, brand):
        if brand == 'BMW':
            return BMW()
        elif brand == 'BYD':
            return BYD()
        elif brand == 'BenC':
            return BenC()
        else:
            print('未知品牌的汽车!!!')


class BMW:

    def run(self):
        print('BMW车跑的快!')


class BYD:

    def run(self):
        print('BYD车跑的慢!')


class BenC:
    def run(self):
        print('BenC车跑的比较快!')


factory1 = CarFactory()
car1 = factory1.creat_car('BMW')
car1.run()
car2 = factory1.creat_car('BYD')
car2.run()
factory2 = CarFactory()
car3 = factory2.creat_car('BenC')
car3.run()
car4 = factory2.creat_car('QQ')
===================运行结果=========================
CarFactory init ......
BMW车跑的快!
BYD车跑的慢!
BenC车跑的比较快!
未知品牌的汽车!!!
===================运行结果=========================

学习来自:北京尚学堂高琪老师 Python 400集

发布了20 篇原创文章 · 获赞 6 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/XuanAlex/article/details/104613933