Python 入门 之 类的三大关系(依赖 / 组合/ 继承关系)

在面向对象的中,类与类之间存在三种关系:依赖关系、组合关系、继承关系。

1、依赖关系:将一个类的类名或对象当做参数传递给另一个函数被使用的关系就是依赖关系

class People:

    def __init__(self,name):
self.name = name def open(self,bx):
bx.open_door(self) def close(self,bx):
bx.close_door(self) class Refrigerator: def __init__(self,name):
self.name = name def open_door(self,p):
print(f"{p.name} 打开冰箱") def close_door(self,p):
print(f"{p.name} 关闭冰箱") r = People("大魔") # People类实例化一个对象r
aux = Refrigerator("奥克斯") # Refrigerator类实例化一个对象aux
r.open(aux) # 将aux对象当做参数传递给r对象的open方法使用
r.close(aux) # 将aux对象当做参数传递给r对象的close方法使用

2、组合关系:将一个类的对象封装到另一个类的对象的属性中,就叫组合

class Boy:

    def __init__(self,name,g):
self.name = name # self = b
self.g = g # g就是girl类实例化的一个对象内存地址 def eat(self):
print(f"{self.name}和{self.g.age}岁,且{self.g.weight}公斤的{self.g.name}py朋友.一起吃了个烛光晚餐!") def make_keep(self):
self.g.live(f"{self.g.weight}公斤的{self.g.name}给{self.name}踩背") class Girl: def __init__(self,name,age,sex,weight,*args):
self.name = name
self.age = age
self.sex = sex
self.weight = weight
self.args = args def live(self,argv):
print(f"直播内容:{argv}") g = Girl("乔毕得",54,"女",220)
b = Boy("太博",g) # 将对象g当做属性封装到b对象的属性中
b.make_keep()

3、继承关系

(1)什么是面向对象的继承

​ 继承(英语:inheritance)是面向对象软件技术当中的一个概念。如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类别追加新的属性和方法也是常见的做法。

​ 一般静态的面向对象编程语言,继承属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充。

(2)程序中 A(B)

<1> A -- 子类,派生类

<2> B -- 父类,基类,超类

当我们写多个类的时候会发现许多问题如:

class Human:

    def __init__(self,name,age,sex):
self.name = name
self.sex = sex
self.age = age def eat(self):
print("吃") class Dog: def __init__(self, name, age, sex):
self.name = name
self.sex = sex
self.age = age def eat(self):
print("吃") class Cat: def __init__(self, name, age, sex):
self.name = name
self.sex = sex
self.age = age def eat(self):
print("吃") class Pig: def __init__(self, name, age, sex):
self.name = name
self.sex = sex
self.age = age def eat(self):
print("吃")

上述代码重复,这时我们可以简化相关代码如:

class Animal: # 父类
"""
动物类
"""
live = "活的" def __init__(self, name, age, sex):
print("is __init__")
self.name = name
self.sex = sex
self.age = age def eat(self): # self 是函数的位置参数
print("吃") class Human(Animal): # 子类
pass class Dog(Animal): # 子类
pass class Cat(Animal): # 子类
pass class Pig(Animal): # 子类
pass

(3)继承的优点:

<1> 减少重复代码

<2> 结构清晰,规范

<3> 增加耦合性(耦合性不宜多,在精)

(4)继承的分类:

<1> 单继承

<2> 多继承

Python2: python2.2 之前都是经典类,python2.2之后出现了新式类,继承object就是新式类
Python3: 只有新式类,不管你继不继承object都是新式类

(5)单继承:

<1> 通过子类的类名使用父类的属性和方法

class Animal: # 父类

    live = "活的"

    def __init__(self, name, age, sex):
print("is __init__")
self.name = name
self.sex = sex
self.age = age def eat(self): # self 是函数的位置参数
print("吃") class Human(Animal): # 子类
pass class Dog(Animal): # 子类
pass Human.eat(12)
Human.__init__(Human,"大魔",18,"男") print(Human.live)
print(Human.__dict__)

<2> 通过子类的对象使用父类的属性和方法

class Animal: # 父类

    live = "活的"

    def __init__(self, name, age, sex):
print("is __init__")
self.name = name
self.sex = sex
self.age = age def eat(self): # self 是函数的位置参数
print("吃") class Human(Animal): # 子类
pass class Dog(Animal): # 子类
pass p = Human("大魔",18,"男")
d = Dog("remmom",1,'母')
print(d.__dict__)
print(p.__dict__) p = Human("大魔",18,"男")
print(p.live)

(6)查找顺序:

<1> 不可逆(就近原则)

<2> 通过子类,类名使用父类的属性或方法(查找顺序):当前类,当前类的父类,当前类的父类的父类---->

<3> 通过子类对象使用父类的属性或者方法(查找顺序):先找对象,实例化这个对象的类,当前类的父类--->

(7)同时使用子类和父类方法或属性:

<1> 方法一:不依赖(不需要)继承

class Animal: # 父类

    live = "活的"

    def __init__(self, name, age, sex):
# self = p的内存地址
self.name = name
self.sex = sex
self.age = age def eat(self): # self 是函数的位置参数
print("吃") class Human: # 子类 def __init__(self, name, age, sex, hobby):
# print(Animal.live)
# self = p的内存地址
Animal.__init__(self,name,age,sex) # 直接使用Animal类调用Animal类中的方法
self.hobby = hobby class Dog: def __init__(self, name, age, sex, attitude):
# self = p的内存地址
self.name = name
self.sex = sex
self.age = age
self.attitude = attitude # 与Human类进行比较 p = Human("大魔",18,"男","健身")
print(p.__dict__)

<2> 方法二:依赖(需要)继承

class Animal: # 父类

    live = "活的"

    def __init__(self, name, age, sex):
# self = p的内存地址
self.name = name
self.sex = sex
self.age = age def eat(self): # self 是函数的位置参数
print("吃") class Dog(Animal): def __init__(self, name, age, sex, attitude):
# self = p的内存地址
# super(Dog,self).__init__(name,age,sex) # 完整写法
super().__init__(name,age,sex) # 正常写法 # 通过super方法使用父类中的方法
self.attitude = attitude d = Dog("大魔",18,"男","忠诚")
print(d.__dict__)

习题练习:

class Base:
def __init__(self, num):
self.num = num def func1(self):
print(self.num)
self.func2() def func2(self):
print("Base.func2") class Foo(Base):
def func2(self):
print("Foo.func2") obj = Foo(123)
obj.func1()
class Base:
def __init__(self, num):
self.num = num def func1(self):
print(self.num)
self.func2() def func2(self):
print(111, self.num) class Foo(Base):
def func2(self):
print(222, self.num) lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
obj.func1()

(8)多继承

多继承是继承多个父类

​ 多继承中, 存在着这样⼀个问题. 当两个⽗类中出现了重名⽅法的时候. 就会涉及到如何查找⽗类⽅法的这么⼀个问题.即MRO(method resolution order) 问题. 在python中这是⼀个很复杂的问题. 因为在不同的python版本中使⽤的是不同的算法来完成MRO的.

(1)经典类:多继承时从左向右执行

class A:
name = "小宝" class B(A):
name = "太博" class C(A):
name = "marry" class D(B, C):
name = "魔22" class E:
name = "魔11" class F(E):
name = "魔" class G(F, D):
name = "bb" class H:
name = "aaa" class Foo(H, G):
pass f = Foo()
print(f.name) # 结果为aaa

总结:

经典类:(深度优先)左侧优先,一条路走到头,找不到会回到起点向右查询

(2)新式类:采用c3算法 (也有说用广度优先的 -- 不精确)

# 下述例子在python2.7中运行
class O(object):
name = "小宝" class D(O):
name = "天魔" class E(O):
name = "太博" class F(O):
name = "marry" class B(D,E):
pass class C(E,F):
name = "金刚" class A(B,C):
pass a = A()
print a.name # 结果为 天魔

(3)c3 算法的核心 mro

<1> mro() -- python提供的可以查看多继承时的执行顺序的一种方法
<2> MRO是一个有序列表L,在类被创建时就计算出来。通用计算公式为:
mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )
(其中Child继承自Base1, Base2)
如果继承至一个基类:class B(A) 这时B的mro序列为
mro( B ) = mro( B(A) )
= [B] + merge( mro(A) + [A] )
= [B] + merge( [A] + [A] )
= [B,A]
如果继承至多个基类:class B(A1, A2, A3 …) 这时B的mro序列
mro(B) = mro( B(A1, A2, A3 …) )
= [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
= ...
计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。
<3> 表头和表尾
表头:   列表的第一个元素
表尾:   列表中表头以外的元素集合(可以为空)

示例   列表:[A, B, C]   表头是A,表尾是B和C

<4> 列表之间的+操作

+操作:

[A] + [B] = [A, B] (以下的计算中默认省略) ---------------------

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操作 ......
---------------------
<5> 经典类不能使用mro , 新式类才能使用mro

Python 入门 之 类的三大关系(依赖 / 组合/ 继承关系)的更多相关文章

  1. Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态)

    Python 入门 之 面向对象的三大特性(封装 / 继承 / 多态) 1.面向对象的三大特性: (1)继承 ​ 继承是一种创建新类的方式,在Python中,新建的类可以继承一个或多个父类,父类又可以 ...

  2. Python 入门 之 类成员

    Python 入门 之 类成员 1.类的私有成员: 私有: 只能自己拥有 以 __ 开头就是私有内容 对于每一个类的成员而言都有两种形式: - 公有成员,在任何地方都能访问 - 私有成员,只有在类的内 ...

  3. Python 入门 之 类的约束以及super()剖析

    Python 入门 之 类的约束以及super()剖析 1.类的约束 第一版: class WechatPay: def pay(self): print("微信支付") clas ...

  4. 第9章 Java类的三大特性之一:继承

    1.什么是继承 子类继承父类就是对父类的扩展,继承时会自动拥有父类所拥有的处private之外的所有成员作用:增加代码复用语法格式: class 子类名 extends 父类名{…………}第9章 Ja ...

  5. 转 OC温故:类的三大特性(封装,继承,多态)

    原文标题:OC学习篇之---类的三大特性(封装,继承,多态) 我们都知道,面向对象程序设计中的类有三大特性:继承,封装,多态,这个也是介绍类的时候,必须提到的话题,那么今天就来看一下OC中类的三大特性 ...

  6. python入门17 类和对象

    类:一类事物的抽象化.概念: 类的变量(属于类的变量,定义在类的开始处)  成员变量(self.变量) 类的方法( @classmethod,cls参数)   成员方法( self参数 )  静态方法 ...

  7. OC学习篇之---类的三大特性(封装,继承,多态)

    之前的一片文章介绍了OC中类的初始化方法和点语法的使用:http://blog.csdn.net/jiangwei0910410003/article/details/41683873,今天来继续学习 ...

  8. Python入门:类与类的继承

    类,是一些有共同特征和行为事物的抽象概念的总和. 1. 定义一个类: 我们使用class来定义一个类,和之前说过的定义函数用def类似.在类里面给变量赋值时,专业术语称之为类的属性. 比如拿可口可乐来 ...

  9. Python进阶-XV 类和对象的命名空间 组合

    一.类和对象命名空间 1.类中可以定义两种属性 静态属性和动态属性 class Course: language = 'Chinese' # 静态属性 def __init__(self, name, ...

随机推荐

  1. 关于MapReduce的测试

    题目:数据清洗以及结果展示 要求: Result文件数据说明: Ip:106.39.41.166,(城市) Date:10/Nov/2016:00:01:02 +0800,(日期) Day:10,(天 ...

  2. JavaWeb_(Struts2框架)struts.xml核心配置、动态方法调用、结果集的处理

    此系列博文基于同一个项目已上传至github 传送门 JavaWeb_(Struts2框架)Struts创建Action的三种方式 传送门 JavaWeb_(Struts2框架)struts.xml核 ...

  3. 读redux源码总结

    redux介绍 redux给我们暴露了这几个方法 { createStore, combineReducers, bindActionCreators, applyMiddleware, compos ...

  4. VLC和Qt结合编写流媒体rtsp播放器

            VLC播放器是一款功能强大且小巧的播放器,它支持多种多样的音视频格式,比如MPEG1,2以及mp3等等.并且通过Qt和VLC的结合能让每个开发者写出自己的视频流媒体播放器.     Q ...

  5. android canvas drawtext 字高

    Paint pFont = new Paint(); Rect rect = new Rect(); pFont.getTextBounds("豆", 0, 1, rect); L ...

  6. AttributeError:module 'keras.engine.topology' has no attribute 'load_weights_from_hdf5_group_by_name

    在jupyter notebooks上运行tensorflow-keras的Mask R-CNN时遇到如下错误: 参考博客中写了两种解决方案: 解决方案一:报错是由于keras版本不对造成的.load ...

  7. kernel hacking的一些网站

    很全面的网站,下面的网站基本都可以从该地址找到. 新手必备 subscrible/unsubscrible mail list mail list archive kernel git mainlin ...

  8. Struts2常量_Action配置路径_通配符

    Struts2中常用的常量 指定默认编码集,作用于HttpServletRequest的setCharacterEncoding方法 和freemarker .velocity的输出 <cons ...

  9. JSTL核心标签库详解

    <c:out>标签 标签用于输出一段文本到浏览器中. 属性名 是否支持EL 属性类型 属 性 描 述 value true Object 指定要输出的内容 escapeXml true B ...

  10. promise 实现红绿灯

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...