首页 > 其他分享 >面向对象的三大特性及派生和组合

面向对象的三大特性及派生和组合

时间:2024-01-12 21:34:53浏览次数:32  
标签:__ name 派生 self 面向对象 三大 print class def

面向对象的三大特性

  • 面向对象编程有三大特性:
    • 封装、继承、多态 --> 派生和组合

【一】封装

【1】什么是封装

  • 在程序设计中,封装(Encapsulation)是对具体对象的一种抽象
  • 封装就是对具体对象的一种抽象
  • 简单理解就是将不想让别人看到的东西全部藏起来

【2】为什么要封装

  • 封装数据的主要原因是:保护隐私(把不想别人知道的东西封装起来)

【3】封装的方法---隐藏属性

在类外部,调用不到,两个 _ 及以上封装起来的属性

隐藏数据属性

class A:
    name = 'aa'
    _name = 'aa_'
    __name = 'aa__'

    def run(self):
        ...

a = A()
print(a.name)  # aa
print(a._name)  # aa_
print(a.__name)  # AttributeError: 'A' object has no attribute '__name'

开放接口:修改隐藏属性age值

class Student:
    def __init__(self, age):
        self.__age = age

    # 对外提供访问接口
    def get_info(self):
        print(self.__age)

    # 对外提供设置接口
    def set_info(self, age):
        self.__age = age


student = Student(18)
student.get_info()  # 18
student.set_info(22)
student.get_info()  # 22

隐藏函数属性

  • 目的的是为了隔离复杂度
class A:
    def __init__(self, name):
        self.name = name

    def run(self):
        print(f'{self.name}在跑步')

    def _run(self):
        print(f'{self.name}在跑步')

    def __run(self):
        print(f'{self.name}在跑步')


a = A(name='qc')

a.run()  # qc在跑步
a._run()  # qc在跑步
a.__run()  # AttributeError: 'A' object has no attribute '__run'

【4】总结

  • 封装数据属性,在类内部,没有用 _ 或者用一个 _ 封装起来的属性,在类内部可以任意访问,在类外部(对象)也可以随意访问

  • 封装数据属性,在类内部,用 __ 封装起来的属性,在类内部可以任意访问,在类外部(对象)不可以访问

  • 封装函数属性,在类内部,没有用 _ 或者用一个 _ 封装起来的属性,在类内部可以任意访问,在类外部(对象)也可以随意访问

  • 封装函数属性,在类内部,用 __ 封装起来的属性,在类内部可以任意访问,在类外部(对象)不可以访问

【二】继承

【1】什么是继承

  • 继承是一种创建新类的方式,新建的类可以继承一个或多个父类(python支持多继承),父类又可称为基类或超类,新建的类称为派生类或子类。
  • 子类会“”遗传”父类的属性,从而解决代码重用问题(去掉冗余的代码)
  • python中类的继承分为:单继承和多继承

【2】单继承和多继承

# 定义父类
class A:
    pass

# 定义父类
class B:
    pass

# 单继承
class C(A):
    pass

# 多继承
class D(A, B):
    pass

# 看所有继承的父类
print(C.__bases__)
# (<class '__main__.A'>,)
print(D.__bases__)
# (<class '__main__.A'>, <class '__main__.B'>)

【3】经典类与新式类

  • 只有在python2中才分新式类和经典类,python3中统一都是新式类
  • 在python2中,没有显式的继承object类的类,以及该类的子类,都是经典类
  • 在python2中,显式地声明继承object的类,以及该类的子类,都是新式类
  • 在python3中,无论是否继承object,都默认继承object,即python3中所有类均为新式类

【4】继承与抽象(先抽象再继承)

  • 继承描述的是子类与父类之间的关系,是一种什么是什么的关系。
  • 要找出这种关系,必须先抽象再继承
  • 抽象即抽取类似或者说比较像的部分

抽象

  • 抽象分成两个层次
    • 将奥巴马和梅西这俩对象比较像的部分抽取成类;
    • 将人,猪,狗这三个类比较像的部分抽取成父类。
  • 抽象最主要的作用是划分类别(可以隔离关注点,降低复杂度)

img

继承

  • 继承:是基于抽象的结果,通过编程语言去实现它,肯定是先经历抽象这个过程,才能通过继承的方式去表达出抽象的结构。
  • 抽象只是分析和设计的过程中,一个动作或者说一种技巧,通过抽象可以得到类

img

继承的代码实现

class A:
    def eat(self):
        print(f"{self.name} 吃饭" )


class B(A):
    def __init__(self, name):
        self.name = name


a = B('cat')
a.eat()  # cat 吃饭

【5】属性查找顺序

  • 属性查找顺序

  • 继承的顺序:从上至下继承

  • 属性查找:从下至上查找

class A:
    def f1(self):
        print('A.f1')

    def f2(self):
        print('A.f2')
        self.f1()

class B(A):
    def f1(self):
        print('B.f1')

b = B()

b.f2()
# A.f2
# B.f1

隐藏属性: 隐藏给当前类,除了当前类,其他继承的子类均不能找到我隐藏的属性

class A:
    def __f1(self):
        print('A.f1')

    def f2(self):
        print('A.f2')
        self.__f1()

class B(A):
    def __f1(self):
        print('B.f1')


b = B()

b.f2()
# A.f2
# A.f1

【6】继承实现的原理

(一)非菱形结构继承顺序

  • 在Java和C#中子类只能继承一个父类,而Python中子类可以同时继承多个父类,如A(B,C,D)
  • 如果继承关系为非菱形结构,则会按照先找B这一条分支,然后再找C这一条分支,最后找D这一条分支的顺序直到找到我们想要的属性

(二)菱形结构继承顺序

  • 如果继承关系为菱形结构,那么属性的查找方式有两种,分别是:深度优先和广度优先
  • python3中统一都是新式类
  • pyhon2中才分新式类与经典类
深度优先
  • 当类是经典类时,多继承情况下,在查找属性不存在时,会按照深度优先的方式查找下去

img

广度优先
  • 当类是新式类时,多继承情况下,在查找属性不存在时,会按照广度优先的方式查找下去

img

代码
class A(object):
    def test(self):
        print('A')


class B(A):
    def test(self):
        print('B')


class C(A):
    def test(self):
        print('C')


class D(B):
    def test(self):
        print('D')


class E(C):
    def test(self):
        print('E')


class F(D, E):
    pass


class G(F, D, E):
    pass


f1 = F()
f1.test()  # D
print(F.__mro__)
# (<class '__main__.F'>, <class '__main__.D'>, <class '__main__.B'>, <class '__main__.E'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

【7】继承的延伸 : 派生

(一)什么是派生

派生是指,子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法

(二)派生的使用

  • 指名道姓的调用某一个类的函数
class A:
    def __init__(self, name):
        self.name = name

class B(A):
    def __init__(self, name, age):
        # 调用的是函数,因而需要传入self
        A.__init__(self, name)
        self.age = age

obj = B('cat', 18)
print(obj.name, obj.age)  # cat 18
  • 超类 super()
    • 调用super()会得到一个特殊的对象
    • 该对象专门用来引用父类的属性
    • 且严格按照MRO规定的顺序向后查找
class A:
    def __init__(self, name):
        self.name = name


class B(A):
    def __init__(self, name, age):
        # 调用的是绑定方法,因此会自动传入self,但是需要传入相应的参数
        super().__init__(name)
        self.age = age

obj = B('cat', 18)
print(obj.name, obj.age)  # cat 18

(三)总结

  • 这两种方式的区别是:
    • 方式一是跟继承没有关系的,而方式二的super()是依赖于继承的
    • 并且即使没有直接继承关系,super()仍然会按照MRO继续往后查找

【8】 组合

(一)什么是组合

  • 在一个类中以另外一个类的对象作为数据属性,称为类的组合。

组合与继承都是用来解决代码的重用性问题。

不同的是:

  • 继承是一种“是”的关系,比如老师是人、学生是人,当类之间有很多相同的之处,应该使用继承;
  • 而组合则是一种“有”的关系,比如老师有生日,老师有多门课程,当类之间有显著不同,并且较小的类是较大的类所需要的组件时,应该使用组合

(二)组合的使用

class Course:
    def __init__(self, name, period, price):
        self.name = name
        self.period = period
        self.price = price

    def tell_info(self):
        print(f'当前课程名字 {self.name}')


class People:
    school = '清华大学'

    def __init__(self, name, sex, age):
        self.name = name
        self.sex = sex
        self.age = age


class Teacher(People):

    def __init__(self, name, sex, age):
        super().__init__(name, age, sex)
        # 实例化后,往该列表中添加Course类的对象
        self.courses = []

    def teach(self):
        print(f'当前老师正在授课 {self.name}')


python = Course('python', '5', 300)
linux = Course('go', '20', 500)
teacher = Teacher('qc', 'male', 20)

# teacher有两门课程
teacher.courses.append(python)
teacher.courses.append(linux)

# 重用Course类的功能
for obj in teacher.courses:
    obj.tell_info()
# 当前课程名字 python
# 当前课程名字 go

(三)总结

​ 组合指的是将不同的类或对象组合在一起以创建更复杂的对象或数据结构。在组合中,一个类可以包含其他类的实例作为其属性,从而实现了对象之间的关联和协作。这种关联关系可以用于构建更复杂的系统,同时保持代码的模块化和可维护性。

【9】组合和继承的区别

组合与继承都是有效地利用已有类的资源的重要方式。但是二者的概念和使用场景皆不同。

(一)继承的方式

  • 通过继承建立了派生类与基类之间的关系,它是一种'是'的关系,比如白马是马,人是动物。
  • 当类之间有很多相同的功能,提取这些共同的功能做成基类,用继承比较好,比如老师是人,学生是人

(二)组合的方式

  • 用组合的方式建立了类与组合的类之间的关系,它是一种‘有’的关系,比如教授有生日,教授教python和linux课程,教授有学生s1、s2、s3...

【三】多态

【1】什么是多态

  • 多态指的是一类事物有多种形态

  • 比如动物,猪狗牛羊猴

import abc


# 同一类事物:动物
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def talk(self):
        pass

# 动物的形态之一:人
class People(Animal):
    def talk(self):
        print('你真帅')

# 动物的形态之二:狗
class Dog(Animal):
    def talk(self):
        print('汪汪汪')
  • 文件有多种形态:文本文件,可执行文件
import abc


# 同一类事物:文件
class File(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def click(self):
        pass

# 文件的形态之一:文本文件
class Text(File):  
    def click(self):
        print('open file')

# 文件的形态之二:可执行文件
class ExeFile(File):  
    def click(self):
        print('execute file')

【2】多态动态绑定(多态性)

  • 多态动态绑定在继承的背景下使用时,有时也称为多态性
  • 多态性是指在不考虑实例类型的情况下使用实例

静态多态性

  • 如任何类型都可以用运算符 + 进行运算

动态多态性

import abc

# 同一类事物:动物
class Animal(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def talk(self):
        pass

# 动物的形态之一:人
class People(Animal):
    def talk(self):
        print('你真帅')

# 动物的形态之二:狗
class Dog(Animal):
    def talk(self):
        print('汪汪汪')
p = People()
dog = Dog()
p.talk()  # 你真帅
dog.talk()  # 汪汪汪

更进一步,我们可以定义一个统一的接口来使用

def func(obj):
    obj.talk()

func(p)  # 你真帅
func(dog)  # 汪汪汪

【3】多态性的好处

  • 增加程序的灵活性和可扩展性

【4】鸭子类型

  • 鸭子类型是一种编程风格,决定一个对象是否有正确的接口
  • 如果它看起来像鸭子,像鸭子一样嘎嘎叫,那么它一定是鸭子。
class NormalDuck():
    def eat(self):
        print(f"正常鸭子可以吃饭")

    def walk(self):
        print(f"正常鸭子可以走路")


class RockDuck():
    def eat(self):
        print(f"肉鸭子可以吃饭")

    def walk(self):
        print(f"肉鸭子可以走路")

标签:__,name,派生,self,面向对象,三大,print,class,def
From: https://www.cnblogs.com/unrealqcc/p/17961641

相关文章

  • java基础语法面向对象之单个对象内存图
    一:概述在面向对象的学习中,需要去了解对象的内存图,在这里以单个对象的内存图为例进行讲解。二:具体说明<1>代码publicclassStudent{Stringname;intage;publicvoidstudy(){System.out.println(name+"好好学习");......
  • Python面向对象之绑定方法和非绑定方法
    绑定方法与非绑定方法【一】概要在Python中,绑定方法是指将类的实例与类的方法关联起来的过程。绑定方法包含类实例作为第一个参数,通常被称为self。当通过实例调用类的方法时,Python会自动传递实例作为第一个参数,这个过程就是方法绑定。【二】常用方法【1】绑定方法(动态方......
  • 精益生产:三大特征及其在实践中的应用
    在当今全球竞争激烈的市场环境中,企业为了保持竞争优势,必须采用一种高效、低成本、高质量的生产方式。精益生产作为一种先进的生产方式,已经成为众多企业的选择。精益生产的核心在于其三大特征:拉动式生产、消除浪费和自働化。这些特征使得企业能够更好地应对市场变化,提高生产效率和质......
  • 29-Scala-面向对象
    1.面向对象编程基础1.1定义类基本语法:[修饰符]class类名{//code}Scala语法中,类并不声明为public,所有这些类都具有公有可见性(即默认就是public)一个Scala源文件可以包含多个类1.2成员变量属性的定义语法同变量:[访问修饰符]var属性名称[:类型]=属性值......
  • Python教程(22)——Python面向对象的属性和方法
    在Python面向对象编程中,属性和方法是类及其对象的重要组成部分。如果说封装、继承和多态是面向对象编程中的思想,那么类的属性和方法就是骨架,因为有属性和方法,面向对象编程才变的有血有肉。属性属性是类或对象所拥有的数据,它用于描述对象的特征和状态。属性可以是实例属性(对象特......
  • 韩顺平java基础-10-面向对象编程
    韩顺平java基础-10-面向对象编程类变量和类方法类变量static静态变量被同一个类所有对象共享类变量在类加载的时候生成定义语法访问修饰符static数据类型变量名如何访问类变量类名.类变量名//类变量随着类加载而创建,所以即使没有创建对象实例也可以访问。使用细......
  • Python面向对象三大特性之封装
    【一】面向对象的三大特性面向对象编程有三大特性:封装、继承、多态其中最重要的一个特性就是封装。封装指的就是把数据与功能都整合到一起听起来是不是很熟悉,没错,我们之前所说的”整合“二字其实就是封装的通俗说法。除此之外,针对封装到对象或者类中的属性,我们还可以......
  • Python 面向对象
    面向对象技术简介类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。数据成员:类变量或者实例变量......
  • java面向对象 + 内存解析
    这篇博客主要是重点讲解一些内存和一些规定的解释,对于定义我不会过多赘述,没有Java基础的话可以去翻看我之前的博客,学习完成之后再进行阅读。面向对象可以说是Java中最重要的一部分了,这次复习我发现有几个点比较重要,这里分享给大家引入:小明今天想要一辆玩具车,他获取这辆玩具车有两......
  • Python教程(20)——python面向对象编程基本概念
    面向对象(Object-oriented)是一种常用的程序设计思想,它以对象作为程序的基本单元,将数据和操作封装在一起,通过对象之间的交互来实现程序的功能。在面向对象编程中,将问题抽象成对象,而对象可以拥有属性(数据)和方法(操作)。对象可以被看作是现实世界中的实体或概念,具有某种特定的状态和行......