Python基础系列之封装继承多态【15】

目标

  • 温故面向对象三大特性
    • Python的私有是真的吗?
    • Python的多继承是什么?
  • 了解下魔方方法

第一部分 魔法方法

相信我们初学者都会有个疑问,下边的意思是啥??为啥要写这个?

反正我是先忽略这个问题,打算在学的过程中慢慢明白😆

if __name__ == '__main__' :

知乎的回答
__name__ 是当前模块名,当模块被直接运行时模块名为 __main__ 。这句话的意思就是,当模块被直接运行时,以下代码块将被运行,当模块是被导入时,代码块不被运行。

还有很多类似的,比如:

__init__ :      构造函数,在生成对象时调用
__del__ : 析构函数,释放对象时使用
__repr__ : 打印,转换
__setitem__ : 按照索引赋值
__getitem__: 按照索引获取值
__len__: 获得长度
__cmp__: 比较运算
__call__: 调用
__add__: 加运算
__sub__: 减运算
__mul__: 乘运算
__div__: 除运算
__mod__: 求余运算
__pow__: 幂

使用实例,比如:

>>> len('ABC')
3
>>> 'ABC'.__len__()
3

class Foo:
def __del__(self):
print("我被回收了!")
obj = Foo()
del obj

等用到了,再看下 😆

第二部分 封装继承多态

封装
封装:将内部实现包裹起来,对外透明,提供api接口进行调用的机制

优点

1. 将变化隔离;
2. 便于使用;
3. 提高复用性;
4. 提高安全性;

原则

1. 将不需要对外提供的内容都隐藏起来;
2. 把属性都隐藏,提供公共方法对其访问。

继承
即一个派生类(derived class)继承父类(base class)的变量和方法。

多态:根据对象类型的不同以不同的方式进行处理。

前提:①类的继承关系 ②要有方法重写。

父类替换子类: super(子类名, self).方法名()

以上概念将通过以下几个实例来说明:

实例一 基本、继承

首先试着下边的三个问题与代码的结果

1. Python的私有方法真的私有吗?
2. Python外部是否可以更改私有属性?
3. 关键字property是什么意思?
# 定义基类
class Person():
def __init__(self, sex, age):
self.age = age
# 定义一个私有变量
self.__sex = sex

def speak(self):
print("性别:%s 年龄:%d " % (self.__sex, self.age))


base = Person(1, 100)
print(base.speak())
print(base.age)
# 调用私用变量: _类名__属性
print(base._Person__sex)
# print(base.__sex)
# AttributeError: 'Person' object has no attribute '__sex'

print("===以上区分调用变量====")


class User(Person):
def __init__(self, sex, age, name):
# 调用父类的实例化方法
Person.__init__(self, sex, age)
self.name = name

def __hide(self):
print('示范隐藏的hide方法')

def getHeight(self):
return self.__height

def setetHeight(self, height):
if height <= 0 or height > 300:
raise ValueError('身高必须在0~300cm之间')
self.__height = height

# property 将geter seter实例为类变量
height = property(getHeight, setetHeight)


# 创建User对象
u = User("男", 20, "Python")
print(u.name)
# seter 方法过滤判断
# u.height = 0
'''
File "class.1.py", line 47, in <module>
u.height = 0
File "class.1.py", line 37, in setetHeight
raise ValueError('身高必须在0~300cm之间'
'''
# 走setter方法
u.height = 1
print(u.height)
# 直接更改内部变量
u._User__height = 0
print(u._User__height)
print(u.height)

其实也不难

结果

性别:1 年龄:100 
# 为何是打印None?
None
100
1
===以上区分调用变量====
Python
1
0
0

实例二 多继承

该部分摘录自Python的方法解析顺序(MRO)

先思考几个问题:

  1. 多继承顺序的规则是什么?
  2. Python中MRO的三种方式是什么?
# 模块inspect:检查运行模块的一些基本信息
import inspect
class A:
def show(self):
print("A.show()")

class B(A):
pass

class C(A):
def show(self):
print("C.show()")

class D(B, C):
pass

# __mro__ 等价于 inspect.getmro
# print(D.__mro__)
print(inspect.getmro(D))
x = D()
x.show()

菱形

按照深度遍历,其顺序为 [D, B, A, object, C, A, object],重复类只保留最后一个,因此变为 [D, B, C, A, object]

结果是

(<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)
C.show()

Python 至少有三种不同的 MRO:

1. 经典类(classic class)的深度遍历。
2. Python 2.2 的新式类(new-style class)预计算。
3. Python 2.3 的新式类的 C3 算法。它也是 Python 3 唯一支持的方式。
  1. 经典类

经典类的遍历顺序为: 从左至右的深度优先遍历。以上述「菱形继承」为例,其查找顺序为 [D, B, A, C, A],如果只保留重复类的第一个则结果为 [D, B, A, C]

  1. 2.2 新式类的执行结果如上例子所示,但其中有问题,

  2. C3 现在Python采用的方式

# 例子
>>> class D(object): pass
>>> class E(object): pass
>>> class F(object): pass
>>> class B(D, E): pass
>>> class C(D, F): pass
>>> class A(B, C): pass
# 结果
>>> A.__mro__
(<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.E'>, <class '__main__.F'>, <type 'object'>)

L[object] = [object]
L[D] = [D, object]
L[E] = [E, object]
L[F] = [F, object]
L[B] = [B, D, E, object]
L[C] = [C, D, F, object]
L[A] = [A] + merge(L[B], L[C], [B], [C])
= [A] + merge([B, D, E, object], [C, D, F, object], [B], [C])
= [A, B] + merge([D, E, object], [C, D, F, object], [C])
= [A, B, C] + merge([D, E, object], [D, F, object])
= [A, B, C, D] + merge([E, object], [F, object])
= [A, B, C, D, E] + merge([object], [F, object])
= [A, B, C, D, E, F] + merge([object], [object])
= [A, B, C, D, E, F, object]

说实在的没看懂

最近没更新,是在找学数学方面的资源,
很开心,正在学

实例三 多态

这个似乎很好理解

class Animal:
def kind(self):
print("i am animal")

class Dog(Animal):
def kind(self):
print("i am a dog")

class Cat(Animal):
def kind(self):
print("i am a cat")

# 这个函数接收一个animal参数,并调用它的kind方法
def show_kind(animal):
animal.kind()

d = Dog()
c = Cat()

show_kind(d)
show_kind(c)

'''
i am a dog
i am a cat
'''

实例四 super

如果想让父类替换子类,那么既可以用super()

class A:
def __init__(self, name):
self.name = name
print("父类的__init__方法被执行了!")
def show(self):
print("父类的show方法被执行了!")

class B(A):
def __init__(self, name, age):
# super(子类名, self).方法名()
super(B, self).__init__(name=name)
self.age = age

def show(self):
super(B, self).show()

obj = B("jack", 18)
obj.show()

参考链接

Python的方法解析顺序(MRO)

图解Python 【第六篇】:面向对象-类-进阶篇
堆栈
内存管理
内存
深入内存
python内存管理–分层分配】
内存

Python的方法解析顺序(MRO)