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的面向对象编程. 如果你以前没有接触过面向对象的编程语言 ...
随机推荐
- Reactive Extensions (Rx) 入门(5) —— Rx的事件编程
译文:https://blog.csdn.net/fangxing80/article/details/7749907 原文:http://www.atmarkit.co.jp/fdotnet/int ...
- bzoj4066: 简单题 K-Dtree
bzoj4066: 简单题 链接 bzoj 思路 强制在线.k-dtree. 卡常啊.空间开1e6就T了. 代码 #include <bits/stdc++.h> #define my_m ...
- while循环 运算符和编码
昨日回顾 1. 初识python python是一门弱类型的解释型高级编程语言 解释器: CPython 官方提供的默认解释器. c语言实现的 PyPy 把python程序一次性进行编译. IPyth ...
- Python 元编程
1.为函数添加包装器 总是存在这样的场景,在一个函数执行前后需要做一些操作处理,常见于日志创建.权限认证或者性能分析等.但有一个问题存在,那就是被装饰的函数,其元信息会丢失,函数引用会指向装饰器的返回 ...
- vlc for mac设置中文的方法
VLC for mac是一款mac系统下的多媒体播放器,支持播放MPEG-1.MPEG-2.MPEG-4.DivX.MP3和OGG,以及DVD.VCD.等各种流媒体协议在内的多种协议格式,并且能够对电 ...
- Mysql中联合索引的最左匹配原则(百度)
创建联合索引时列的选择原则 经常用的列优先(最左匹配原则) 离散度高的列优先(离散度高原则) 宽度小的列优先(最少空间原则) 在Mysql建立多列索引(联合索引)有最左前缀的原则,即最左优先.如果我们 ...
- Arbitrary Style Transfer in Real-time with Adaptive Instance Normalization
Arbitrary Style Transfer in Real-time with Adaptive Instance Normalization 2019-10-10 10:50:19 Paper ...
- clumsy 模拟网络丢包延迟
https://www.cnblogs.com/bodboy/p/6015530.html clumsy 能在 Windows 平台下人工造成不稳定的网络状况,方便你调试应用程序在极端网络状况下的表现 ...
- odoo开发笔记 -- 当前时间&时间运算相关
当前日期/时间: from datetime import datetime, timedelta now_time = datetime.now() today_date_format = now_ ...
- 【转】CAD 二次开发--属性块 Block和BlockReference
1.属性块的定义 属性块是有构成的实体和附加信息(属性)组成的,属性块中块的定义与简单块中块的定义一样,而属性的定义主要是通过属性的AttributeDefinition类的有关属性和函数来实现的.具 ...