Python基础--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类实例化一个对象raux = Refrigerator("奥克斯")   # Refrigerator类实例化一个对象auxr.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): # 子类
    passclass Dog(Animal):  # 子类
    passclass Cat(Animal):  # 子类
    passclass 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): # 子类
    passclass 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): # 子类
    passclass 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 = hobbyclass 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):
    passf = 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):
    passclass C(E,F):
    name = "金刚"class A(B,C):
    passa = 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 进行
目录
相关文章
|
15天前
|
缓存 监控 程序员
Python中的装饰器是一种特殊类型的声明,它允许程序员在不修改原有函数或类代码的基础上,通过在函数定义前添加额外的逻辑来增强或修改其行为。
【6月更文挑战第30天】Python装饰器是无侵入性地增强函数行为的工具,它们是接收函数并返回新函数的可调用对象。通过`@decorator`语法,可以在不修改原函数代码的情况下,添加如日志、性能监控等功能。装饰器促进代码复用、模块化,并保持源代码整洁。例如,`timer_decorator`能测量函数运行时间,展示其灵活性。
18 0
|
10天前
|
设计模式 开发者 Python
Python中循环依赖问题及其解决方案
循环依赖是 Python 开发中需要特别注意的问题。通过重新设计模块结构、延迟导入、依赖注入、利用 Python 的动态特性以及代码重构等方法,可以有效地解决循环依赖问题。这些策略不仅有助于提高代码的可维护性和可读性,还能避免潜在的运行时错误。在实际开发中,开发者应该根据具体情况选择合适的解决方案。
|
12天前
|
存储 JSON 测试技术
python中json和类对象的相互转化
针对python中类对象和json的相关转化问题, 本文介绍了4种方式,涉及了三个非常强大的python库jsonpickle、attrs和cattrs、pydantic,但是这些库的功能并未涉及太深。在工作中,遇到实际的问题时,可以根据这几种方法,灵活选取。 再回到结构化测试数据的构造,当需要对数据进行建模时,也就是赋予数据业务含义,pydantic应该是首选,目前(2024.7.1)来看,pydantic的生态非常活跃,各种基于pydantic的工具也非常多,建议尝试。
|
19天前
|
Python
Python面向对象进阶:深入解析面向对象三要素——封装、继承与多态
Python面向对象进阶:深入解析面向对象三要素——封装、继承与多态
|
19天前
|
Python
Python面向对象基础与魔法方法详解
Python面向对象基础与魔法方法详解
|
19天前
|
算法 Python
Python新式类和经典类
Python新式类和经典类
|
19天前
|
Python
python面向对象
python面向对象
10 1
|
21天前
|
安全 测试技术 Python
Python类中的Setter与Getter:跨文件调用的艺术
Python类中的Setter与Getter:跨文件调用的艺术
16 3
|
21天前
|
SQL 分布式计算 大数据
MaxCompute产品使用问题之建了一个python 的 UDF脚本,生成函数引用总是说类不存在,是什么导致的
MaxCompute作为一款全面的大数据处理平台,广泛应用于各类大数据分析、数据挖掘、BI及机器学习场景。掌握其核心功能、熟练操作流程、遵循最佳实践,可以帮助用户高效、安全地管理和利用海量数据。以下是一个关于MaxCompute产品使用的合集,涵盖了其核心功能、应用场景、操作流程以及最佳实践等内容。
|
1天前
|
Python
`scipy.signal`模块是SciPy库中的一个子模块,它提供了信号处理、滤波、频谱分析等功能。这个模块包含了许多用于信号处理的函数和类,其中`butter()`和`filtfilt()`是两个常用的函数。
`scipy.signal`模块是SciPy库中的一个子模块,它提供了信号处理、滤波、频谱分析等功能。这个模块包含了许多用于信号处理的函数和类,其中`butter()`和`filtfilt()`是两个常用的函数。
10 0