python基础08-面向对象02-多继承、多态、设计模式、object超类

东阳的学习记录,坚持就是胜利

面向对象三大特征

Python 是面向对象的语言,也支持面向对象编程的三大特性:继承、封装(隐藏)、多态。

继承

Python 支持多重继承,一个子类可以继承多个父类。尽量不要使用多继承,多继承会使逻辑混乱,极大的影响程序可读性。(java中并不支持多继承,使用接口代替。)

Python 支持多重继承,一个子类可以继承多个父类。继承的语法格式如下:

class  子类类名(父类 1[,父类 2,...]):
		类体

如果在类定义中没有指定父类,则默认父类是 object 类。也就是说,object 是所有类的父
类,里面定义了一些所有类共有的默认实现,比如:new()。定义子类时,必须在其构造函数中调用父类的构造函数。调用格式如下:

  • 父类名.init(self, 参数列表)

python继承的基本语法如下:

# 继承
class Person:
    def __init__(self,name,age):
        self.name = name
        self.__age = age
        
    def say_age(self):
        print(self.name,"的年龄是:",self.__age)

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

s1 = Student("张三",15,85)
s1.say_age()
print(dir(s1))  # dir() 打印所有的属性和方法
s1._Person__age

查看类的继承层次结构

通过类的方法 mro()或者类的属性__mro__可以输出这个类的继承层次结构。

class A:pass
class B(A):pass
class C(B):pass
print(C.mro())

执行结果:
[<class ‘main.C’>, <class ‘main.B’>, <class ‘main.A’>, <class ‘object’>]

object根类

object 类是所有类的父类,因此所有的类都有 object 类的属性和方法。我们显然有必要深
入研究一下 object 类的结构。对于我们继续深入学习 Python 很有好处。

dir() 查看对象属性

class Person:def __init__(self,name,age):
	self.name = name
	self.age = age
	
	def say_age(self):
		print(self.name,"的年龄是:",self.age)
		
obj = object()
print(dir(obj))
s2 = Person("高淇",18)
print(dir(s2))
执行结果:
['__class__','__delattr__','__dir__','__doc__','__eq__',
'__format__','__ge__','__getattribute__', '__gt__', '__hash__', '__init__', 
'__init_subclass__', '__le__', '__lt__','__ne__', '__new__', '__reduce__','__reduce_
ex__', '__repr__', '__setattr__', '__sizeof__','__str__', '__subclasshook__']

['__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__', 'age', 'name', 'say_age']

从上面我们可以发现这样几个要点:

  1. Person 对象增加了六个属性:
'__dict__', __module__, __weakref__, age, name, say_age
  1. object 的所有属性,Person 类作为 object 的子类,显然包含了所有的属性。
  2. 我们打印 age、name、say_age,发现 say_age 虽然是方法,实际上也是属性。只不过,
    这个属性的类型是“method”而已。
    age <class ‘int’>
    name <class ‘str’>
    say_age <class ‘method’>

重写object的__str()__方法

# object类和__str__的重写
class Person:
    def __init__(self,name,age):
        self.name = name
        self.__age = age
    def __str__(self):
        '''将对象转化成一个字符串,一般用于 print 方法'''
        return "名字是:{0},年龄是{1}".format(self.name,self.__age)

p = Person("高淇",18)
print(p)

多重继承和MRO()

多重继承尽量不要用。
在这里插入图片描述

MRO

Python 支持多继承,如果父类中有相同名字的方法,在子类没有指定父类名时,解释器将
“从左向右”按顺序搜索。
MRO列表的构造是通过一个C3线性化算法来实现的。 我们不去深究这个算法的数学原理,它实际上就是合并所有父类的MRO列表并遵循如下三条准则:

  • 子类会先于父类被检查
  • 多个父类会根据它们在列表中的顺序被检查
  • 如果对下一个类存在两个合法的选择,选择第一个父类
#多重继承
# MRO()
class A:
    def aa(self):
        print("aa")
    def say(self):
        print("say AAA!")
class B:
    def bb(self):
        print("bb")
    def say(self):
        print("say BBB!")
class C(B,A):
    def cc(self):
        print("cc")
c = C()
print(C.mro()) #打印类的层次结构
c.say() #解释器寻找方法是“从左到右”的方式寻找,此时会执行 B类中的 say()

运行结果:
[<class ‘main.C’>, <class ‘main.B’>, <class ‘main.A’>, <class ‘object’>]
say BBB!

使用super()获得父类定义

当你使用 super() 函数时,Python会在MRO列表上继续搜索下一个类。 只要每个重定义的方法统一使用 super() 并只调用它一次, 那么控制流最终会遍历完整个MRO列表,每个方法也只会被调用一次。

详见: https://python3-cookbook.readthedocs.io/zh_CN/latest/c08/p07_calling_method_on_parent_class.html

多态

多态(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 animalShout(a):
    if isinstance(a,Animal):
        # 传入的对象不同,调用的shout方法对应的实际行动也不同
        a.shout()

animalShout(Dog())
animalShout(Cat())

运行结果:
小狗,汪汪汪
小猫,喵喵喵

特殊方法和运算符重载

Python 的运算符实际上是通过调用对象的特殊方法实现的。比如:

a = 20
b = 30
c = a+b
d = a.__add__(b)
print("c=",c)
print("d=",d)

常见的特殊方法统计

方法说明例子
__init__构造方法 对象创建:p = Person()
__del__析构方法对象回收
__repr__,__str__打印,转换print(a)
__call__函数调用a()
__getattr__点号运算a.xxx
__setattr__属性赋值a.xxx = value
__getitem__索引运算a[key]
__setitem__索引赋值a[key]=value
__len__长度len(a)

每个运算符对应相应的方法

运算符特殊方法说明
运算符+__add__加法
运算符-__sub__减法
<,<=,==__lt__,__le__,__eq__比较运算符
>,>=,!=gt,ge,ne比较运算符
,^,&__or__,__xor__,__and__或、异或、与
<<,>>__lshift__,__rshift__左移、右移
*,/,%,//__mul__,__truediv__,__mod__, __floordiv__,_ 乘、浮点除、模运算_floordiv__ (取余)、整数除
**__pow__指数运算
# 特殊方法和运算符重载
#测试运算符的重载
class Person:
    def __init__(self,name):
        self.name = name
        
    def __add__(self, other):
        if isinstance(other,Person):
            return "{0}--{1}".format(self.name,other.name)
        else:
            return "不是同类对象,不能相加"
    
    def __mul__(self, other):
        if isinstance(other,int):
            return self.name*other
        else:
            return "不是同类对象,不能相乘"

        
p1 = Person("高淇")
p2 = Person("高希希")
x = p1 + p2
print(x)
print(p1*3)

运行结果:
高淇–高希希
高淇高淇高淇

特殊属性

Python 对象中包含了很多双下划线开始和结束的属性,这些是特殊属性,有特殊用法。这
里我们列出常见的特殊属性:

特殊方法含义
obj.__dict__对象的属性字典
obj.__class__对象所属的类
class.__bases__类的基类元组(多继承)
class.__base__类的基类
class.__mro__类层次结构
class.__subclasses__()子类列表
#测试特殊属性
class A:
	pass
class B:
	pass
class C(B,A):
	def __init__(self,nn):
		self.nn = nn
	def cc(self):
		print("cc")
		
c = C(3)
print(dir(c))
print(c.__dict__)
print(c.__class__)
print(C.__bases__)
print(C.mro())
print(A.__subclasses__())

运行结果
[‘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’, ‘cc’, ‘nn’]
{‘nn’: 3}
<class ‘main.C’>
(<class ‘main.B’>, <class ‘main.A’>)
[<class ‘main.C’>, <class ‘main.B’>, <class ‘main.A’>, <class ‘object’>]
[<class ‘main.C’>]

组合

就是套娃,不解释。

设计模式

工厂模式(将类的创建全部交给工厂函数,便于管理)

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

#工厂模式
class CarFactory:
    def createCar(self,brand):
        if brand == "奔驰":
            return Benz()
        elif brand == "宝马":
            return BMW()
        elif brand == '比亚迪':
            return BYD()
        else:
            return "未知品牌,无法创建"

        
class Benz:
    pass
class BMW:
    pass
class BYD:
    pass

factory = CarFactory()
c1 = factory.createCar("奔驰")
c2 = factory.createCar("宝马")
print(c1)
print(c2)

单例模式(一个唯一的全局的实例对象)

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

#单例模式
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)
b = MySingleton("bb")
print(b)

运行结果:
init…
<main.MySingleton object at 0x7fc9b5deca10>
<main.MySingleton object at 0x7fc9b5deca10>

设计模式称之为“模式”,就是一些固定的套路。我们很容易用到其他场景上,比如前面讲的工厂模式,我们需要将工厂类定义成“单例”,只需要简单的套用即可实现:

#测试工厂模式和单例模式的整合使用
class CarFactory:
    __obj = None#类属性
    __init_flag = True
    
    def create_car(self,brand):
        if brand =="奔驰":
            return Benz()
        elif brand =="宝马":
            return BMW()
        elif brand == "比亚迪":
            return BYD()
        else:
            return "未知品牌,无法创建"
    
    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("init CarFactory....")
            CarFactory.__init_flag = False

class Benz:
    pass
class BMW:
    pass
class BYD:
    pass
factory = CarFactory()
c1 = factory.create_car("奔驰")
c2 = factory.create_car("比亚迪")
print(c1)
print(c2)
factory2 = CarFactory()
print(factory)
print(factory2)

运行结果:
init CarFactory…
<main.Benz object at 0x7fc9b5fb9650>
<main.BYD object at 0x7fc9b5bcaf10>
<main.CarFactory object at 0x7fc9b5bca410>
<main.CarFactory object at 0x7fc9b5bca410>

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

东阳z

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值