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的面向对象编程. 如果你以前没有接触过面向对象的编程语言 ...
随机推荐
- 某神奇的cf跳转插件
// ==UserScript== // @name Codeforces快速跳转菜单 // @namespace http://tampermonkey.net/ // @version 2019. ...
- 用正确的姿势使用 celery
简介 celery 是一个简单.灵活.可靠的分布式系统,可以处理大量的消息. celery 是一个任务队列,关注实时处理,同时支持任务调度. 它的工作机制是这样的: 快速使用 安装:pip3 inst ...
- 新手AS常见问题集锦
开发环境 以前开发android的时候可以使用eclipse,虽然现在也能使用eclipse,但是google已经不再支持使用eclipse开发android了.因为google有了自己的IDE--- ...
- ansible-playbook-常用
创建软链:file: - name: create link hosts: "{{hosts_ip}}" tasks: - name: create link file: src= ...
- Google Kick Start 2019 C轮 第一题 Wiggle Walk 题解
Google Kick Start 2019 C轮 第一题 Wiggle Walk 题解 题目地址:https://codingcompetitions.withgoogle.com/kickstar ...
- 如何查看电脑的GPU信息
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/qq_33690342/article/ ...
- Java-JUC(十五):synchronized执行流程分析
一.锁对象及 synchronized 的使用 synchronized 通过互斥锁(Mutex Lock)来实现,同一时刻,只有获得锁的线程才可以执行锁内的代码. 锁对象分为两种: 实例对象(一个类 ...
- win10 安装mysql 8.0.18 解决Navicat初次连接报错
win10 安装mysql 8.0.18 解决Navicat初次连接报错 win10 安装mysql 8.0.18-winx64 一,先去官网下载mysql 安装包 https://dev.mysql ...
- win10系统优化方法及chkdsk工具使用
发现安装了测试版的Win10真的很慢!其实Win10在每次升级后,的确会比老版慢上很多,这只要是因为新增加的安全功能,往往会对系统速度造成拖累.但有很多方法都可以让你的系统运行如飞. http://b ...
- git rebase命令
使用git rebase合并多次commit. 当年提交代码后,管理员发现,你的代码不能提交到服务器上,注意原因在于,你的commit中的commit和服务器中的有些commit不在同一时间轴上,即: ...