20.Python略有小成(面向对象Ⅱ)
Python(面向对象Ⅱ)
一、类的空间问题
何处可以添加对象属性
class A:
def __init__(self,name):
self.name = name
def func(self,sex):
self.sex = sex # 类外面可以:
obj = A('barry')
obj.age = 18
print(obj.__dict__) # {'name': 'barry', 'age': 18} # 类内部也可以:
obj = A('barry') # __init__方法可以。
obj.func('男') # func 方法也可以。 # 总结:对象的属性不仅可以在__init__里面添加,还可以在类的其他方法或者类的外面添加。
何处可以添加类的静态属性
class A:
def __init__(self,name):
self.name = name
def func(self,sex):
self.sex = sex
def func1(self):
A.bbb = 'ccc' # 类的外部可以添加
A.aaa = 'taibai'
print(A.__dict__) # 类的内部也可以添加。
A.func1(111)
print(A.__dict__) # 总结:类的属性不仅可以在类内部添加,还可以在类的外部添加。
对象如何找到类的属性
之前咱们都学习过,实例化一个对象,可以通过点的方式找到类中的属性
那么他为什么可以找到类中的属性呢 , 如下图 :

对象查找属性的顺序:先从对象空间找 ------> 类空间找 ------> 父类空间找
类名查找属性的顺序:先从本类空间找 -------> 父类空间找
单向不可逆,类名不可能找到对象的属性。
对象与对象之间原则上互相独立(除去组合这种特殊的关系外)
二、类与类之间的关系
类与类中存在以下关系:
依赖关系(主从关系)
将一个类的对象或者类名传到另一个类的方法中
class Elephant:
def __init__(self, name):
self.name = name
def e_open(self,ref1):
print(f"{self.name}要开门了,默念三声,开")
ref1.open_door()
def e_close(self,ref2):
print(f"{self.name}要关门了,默念三声,关")
ref2.close_door()
class Refrigerator:
def __init__(self, name):
self.name = name
def open_door(self):
print(f"{self.name}冰箱门被打开了")
def close_door(self):
print(f"{self.name}冰箱门被关上了")
elephant = Elephant('大象')
haier = Refrigerator('美丽')
elephant.e_open(haier)
elephant.e_close(haier)
组合关系(关联,聚合)
这三个在代码写法是一样的,但含义上不一样.
关联关系 : 两种事物必须是互相关联的,但是在某些特殊情况下是可以更改和更换的
class Boy:
def __init__(self,name):
self.name = name
def meet(self,girl_friend=None):
self.girl_friend = girl_friend
def have_a_diner(self):
if self.girl_friend:
print('%s和%s一起晚饭'%(self.name,self.girl_friend.name))
self.girl_friend.shopping(self)
else:
print('一个人吃饭')
class Girl:
def __init__(self,name,age):
self.name = name
self.age = age
def shopping(self,boy_friend):
print(f"{self.name},{boy_friend.name}一起去购物") wu=Boy("老道")
flower=Girl("尼姑",48)
wu.meet(flower)
wu.have_a_diner() # 注意:此时Boy和Girl两个类之间就是关联关系,两个类的对象紧密联系,其中一个如果没有了,另一个就孤单存在,关联关系其实就是当我需要你,你也属于我,这就是关联关系.
聚合关系 : 属于关联关系中的一种特例,侧重点是xxx和xxx聚合成xxx,各有各的声明周期,互相独立.
组合关系 : 属于关联关系中的一种特例,写法上差不多,组合关系比聚合还要紧密,互相关联,将一个类的对象封装到另一个类的对象的属性中,就叫组合
组合关系和聚合关系,其实代码上差别不大,以组合关系举例:
# 设计一个游戏人物类,让实例化几个对象让这几个游戏人物实现互殴的效果,同时增加装备系统.
class Gamerole:
def __init__(self,name,ad,hp):
self.name = name
self.ad = ad
self.hp = hp
def equip_weapon(self,wea):
self.wea = wea # 组合:给一个对象封装一个属性改属性是另一个类的对象
class Weapon:
def __init__(self,name,ad):
self.name = name
self.ad = ad
def weapon_attack(self,p1,p2):
p2.hp = p2.hp - self.ad - p1.ad
print('%s 利用 %s 攻击了%s,%s还剩%s血'
%(p1.name,self.name,p2.name,p2.name,p2.hp)) # 实例化三个人物对象:
barry = Gamerole('师太',10,100)
panky = Gamerole('师爷',20,250)
pillow = Weapon('拖鞋',10) # 给人物装备武器对象。
barry.equip_weapon(pillow) # 开始攻击
barry.wea.weapon_attack(barry,panky) # 注意:上面就是组合,只要是人物.equip_weapon这个方法,那么人物就封装了一个武器对象,再利用武器对象调用其类中的weapon_attack方法。
继承关系
官方说法 : 继承(英语:inheritance)是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。
面向对象的三大特性 : 封装,继承,多态
什么是继承
B继承A类,B就叫做A的子类,A叫做B的父类,基类,超类,B类以及B类的对象使用A类的所有的属性以及方法
举例如下 :
# 正常类的用法
class Person:
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
class Cat:
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
class Dog:
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex # 继承的用法:
class Aniaml(object): # 在这里 Aminal 叫做父类,基类,超类。
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
class Person(Aniaml): # Person: 子类,派生类。
pass
class Cat(Aniaml): # Cat: 子类,派生类。
pass
class Dog(Aniaml): # Dog: 子类,派生类。
pass
继承的优点
- 减少代码重复
 - 增加类的耦合性
 - 代码规范化合理化
 
继承分类
单继承
类名对象执行父类方法,子类以及子类对象只能调用父类的属性以及方法,不能操作(增删改)
class Aniaml(object):
type_name = '动物类'
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print(self)
print('吃东西')
class Person(Aniaml):
pass
class Cat(Aniaml):
pass
class Dog(Aniaml):
pass # 类名:
print(Person.type_name) # 可以调用父类的属性,方法。
Person.eat(111)
print(Person.type_name) # 对象:
# 实例化对象
p1 = Person('师太','女',20)
print(p1.__dict__) # 对象执行类的父类的属性,方法。
print(p1.type_name)
p1.type_name = '666'
print(p1)
p1.eat()
执行顺序
class Aniaml(object):
type_name = '动物类'
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print(self)
print('吃东西')
class Person(Aniaml):
def eat(self):
print('%s 吃饭'%self.name)
class Cat(Aniaml):
pass
class Dog(Aniaml):
pass
p1 = Person('lala','女',20)
# 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
p1.eat()
# 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。
同时执行类以及父类方法
方法一
子类的方法中写上:父类.func(对象,其他参数)
class Aniaml(object):
type_name = '动物类'
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print('吃东西')
class Person(Aniaml):
def __init__(self,name,sex,age,mind):
Aniaml.__init__(self,name,sex,age) # 方法一
self.mind = mind
def eat(self):
super().eat()
print('%s 吃饭'%self.name)
class Cat(Aniaml):
pass
class Dog(Aniaml):
pass # 方法一: Aniaml.__init__(self,name,sex,age)
p1 = Person('师太','女',20,'武艺高强')
print(p1.__dict__)
方法二
利用super,super().func(参数)
class Aniaml(object):
type_name = '动物类'
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex
def eat(self):
print('吃东西')
class Person(Aniaml):
def __init__(self,name,sex,age,mind):
# super(Person,self).__init__(name,sex,age)
# super()括号内可不写Person,self 在python自动执行此操作
super().__init__(name,sex,age) # 方法二
self.mind = mind
def eat(self):
super().eat()
print('%s 吃饭'%self.name)
class Cat(Aniaml):
pass
class Dog(Aniaml):
pass
p1 = Person('师太','女',20,'武艺高强')
print(p1.__dict__)
多继承
class ShenXian:
def fei(self):
print("飞")
class Monkey:
def pi(self):
print("皮")
class SunWukong(ShenXian, Monkey): # 孙悟空是神仙,同时也是也只猴
pass
sxz = SunWukong() # 孙悟空
sxz.pi() # 此时猴子皮
sxz.fei() # 此时会飞
当两个超类中出现了重名方法的时候,这时就涉及到如何查找超类方法的这个问题.即MRO(method resolution order) 问题. 在python中这是个很复杂的问题. 因为在不同的python版本中使用的是不同的算法来完成MRO的.
python中类的种类(继承需要) :
class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
class E:
pass
class F(D, E):
pass
class G(F, D):
pass
class H:
pass
class Foo(H, G):
pass
python2.2之前 : 都是经典类,
python2.2-python2.7存在两种类型 :经典类,新式类
python3x只有新式类
经典类 : 基类不继承object,查询规则依靠深度优先原则(画图)
从头开始,从左往右.,一条路跑到头,然后回头,继续一条路跑到头,就是经典类的MRO算法
Foo-> H -> G -> F -> E -> D -> B -> A -> C

新式类 : 基类必须继承object,查询规则依靠mro算法,mro是一个有序列表L,在类被创建时就计算出来。
通用计算公式为:mro(Child(Base1,Base2))=[Child]+merge( mro(Base1),mro(Base2),[Base1,Base2])
(其中Child继承自Base1, Base2)
merge操作示例:
如计算merge( [E,O], [C,E,F,O], [C] )
有三个列表 : ① ② ③
1 merge不为空,取出第一个列表列表①的表头E,进行判断
各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
2 取出列表②的表头C,进行判断
C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
3 进行下一次新的merge操作 ......
---------------------
计算mro(A)方式:
# mro(A)内部运行情况如下
mro(A) = mro( A(B,C) )
原式= [A] + merge( mro(B),mro(C),[B,C] )
mro(B) = mro( B(D,E) )
= [B] + merge( mro(D), mro(E), [D,E] ) # 多继承
= [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O]
= [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D
= [B,D,E] + merge([O] , [O])
= [B,D,E,O]
mro(C) = mro( C(E,F) )
= [C] + merge( mro(E), mro(F), [E,F] )
= [C] + merge( [E,O] , [F,O] , [E,F] )
= [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除
= [C,E,F] + merge([O] , [O])
= [C,E,F,O]
原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
= [A,B] + merge( [D,E,O], [C,E,F,O], [C])
= [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E
= [A,B,D,C] + merge([E,O], [E,F,O])
= [A,B,D,C,E] + merge([O], [F,O]) # 跳过O
= [A,B,D,C,E,F] + merge([O], [O])
= [A,B,D,C,E,F,O]
---------------------
# python提供了简单的方法查询
python(mro(A)) # 此时会打印出A的超级之间的排序关系
20.Python略有小成(面向对象Ⅱ)的更多相关文章
- 19.Python略有小成(面向对象Ⅰ)
		
Python(面向对象Ⅰ) 一.面向对象初识 回顾面向过程编程与函数式编程 # 面向过程编程 测量对象的元素个个数. s1 = 'fjdsklafsjda' count = 0 for i in s1 ...
 - Python之面向对象一
		
引子 小游戏:人狗大战 角色:人和狗 角色属性:姓名,血量,战斗力和性别(种类) 技能:打/咬 用函数实现人打狗和狗咬人的情形 def Dog(name,blood,aggr,kind): dog = ...
 - [ python ] 初始面向对象
		
首先,通过之前学习的函数编写一个 人狗大战 的例子. 分析下这个需求,人 狗 大战 三个事情.角色:人.狗动作:狗咬人,人打狗 先创建人和狗两个角色: def person(name, hp, ag ...
 - Python -面向对象(一 基本概念)
		
一 Python简单介绍 Python是一个可移植的面向对象的脚本语言. Python尽管是一个脚本语言,但也是一个全然面向对象的语言.由于它设计之初把易用性做为很重要的一个考量标准,所以用起来很简洁 ...
 - Python之面向对象封装
		
Python之面向对象封装 封装不是单纯意义的隐藏 什么是封装: 将数据放在一个设定好的盒子里,并标出数据可以实现的功能,将功能按钮外露,而隐藏其功能的工作原理,就是封装. 要怎么封装: 你余额宝有多 ...
 - Python之面向对象slots与迭代器协议
		
Python之面向对象slots与迭代器协议 slots: # class People: # x=1 # def __init__(self,name): # self.name=name # de ...
 - python初始面向对象
		
阅读目录 楔子 面向过程vs面向对象 初识面向对象 类的相关知识 对象的相关知识 对象之间的交互 类命名空间与对象.实例的命名空间 类的组合用法 初识面向对象小结 面向对象的三大特性 继承 多态 封装 ...
 - Python 基础 面向对象之二 三大特性
		
Python 基础 面向对象之二 三大特性 上一篇主要介绍了Python中,面向对象的类和对象的定义及实例的简单应用,本篇继续接着上篇来谈,在这一篇中我们重点要谈及的内容有:Python 类的成员.成 ...
 - Python 【面向对象】
		
前言 Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的.本章节我们将详细介绍Python的面向对象编程. 如果你以前没有接触过面向对象的编程语言 ...
 
随机推荐
- .net core 原生支持grpc
			
文章转自:https://grpc.io/blog/grpc-on-dotnetcore This is a guest post by Sourabh Shirhatti, a Program Ma ...
 - js实现延迟加载
			
defer async.await 动态创建DOM jQ的getScript()方法 window.onload().$(document).ready() Promise setTimeout.se ...
 - TensorFlow安装笔记(CPU版)
			
新电脑配环境又出了问题. 先是装了最新版anaconda,python3.7的版本.——2019.10.21 然后conda install TensorFlow,conda install kera ...
 - gitlab 上传代码
			
#生成公钥ssh-keygen -t ed25519 -C "xxx@tianwang.com"#拷贝公钥pbcopy < ~/.ssh/id_ed25519.pub 在网页 ...
 - Java中的long类型和Long类型比较大小
			
Java中我们经常要做一些判断,而对于判断的话,用的最多的便是“>”.“==”.“<”的比较,这里我们进行一个Long类型数据和long类型数据的比较大小的讲解. Java中Long和lo ...
 - Mongoose 两个表关联查询aggregate 以及 Mongoose中获取ObjectId
			
Mongoose 两个表关联查询aggregate 通常两个表关联查询的时候,是一种一对多的关系,比如订单与订单详情就是一对多的关系,一个订单下面有多个商品 数据模拟 首先我们先将数据模拟出来,先选择 ...
 - pathlib.Path 类的使用
			
from pathlib import Path 参考 https://www.jb51.net/article/148789.htm
 - 记一次 HttpClient 死锁问题
			
原文:http://blog.kail.xyz/post/2019-04-21/tools/httpclient-lock.html 最近遇到一个使用 Apache HttpClient 过程中的问题 ...
 - C# Microsoft.Office.Interop.Owc11 导出excel文件
			
C# Microsoft.Office.Interop.Owc11 导出excel文件 1.新建项SupremeWindowsForms窗体应用项目(项目平台设置称X86) 注意:因为大多数第三方写的 ...
 - Git Bash 克隆project
			
cd 到想要的路径,然后执行下面的命令