当前位置: 首页 > article >正文

【Python】面对对象超全总结:封装,继承,多态

文章目录

  • 一.类与对象
  • 二.类中的特殊方法
    • 2.1构造方法
    • 2.2魔术方法
  • 三.封装
  • 四.继承
    • 4.1单继承
    • 4.2多继承
    • 4.3重写
  • 五.运算符重载
  • 六.类型注解
    • 6.1变量的类型注解
    • 6.2函数(方法)的类型注解
    • 6.3Union类型
  • 七.多态
  • 八.抽象类(接口)

我们先来看一个使用对象组织数据:

在这里插入图片描述

【代码示例】:

class Student:
    name = None   # 记录学生的姓名
    gender = None  # 记录学生的性别
    nationality = None  # 记录学生国籍
    native_place = None # 记录学生籍贯
    age = None

# 创建一个对象
stu_1 = Student
# 对象属性进行赋值
stu_1.name = "林俊杰"
stu_1.gender = "男"
stu_1.nationality = "中国"
stu_1.native_place = "山东省"
stu_1.age = 31
# 获取对象中的信息
print(stu_1.name)
print(stu_1.gender)
print(stu_1.nationality)
print(stu_1.native_place)
print(stu_1.age)

'''运行结果:
林俊杰
男
中国
山东省
31'''

一.类与对象

类的定义

python中使用class关键字来定义一个类,语法如下:

class 类名:
    属性名 = 属性值
    def 方法名(self,形参1,...,形参n):
        方法体

在类中可以定义对象的属性和方法,属性和方法类似于前面所讲的变量和函数,但类中方法形参表的第一个参数是self,它是一个指代对象的默认参数。

  • 它用来表示类对象自身的意思
  • 当我们使用类对象调用方法时,self会自动被Python传入
  • 在方法内部,想要访问类的成员变量,必须使用self

即在成员方法中访问成员变量,是通过参数列表中self.访问到的

【代码示例】

class Student:
    name = None
    def say_hi(self):
        print(f"大家好,我是{self.name},欢迎大家")
stu = Student()
stu.name = "菜菜"
stu.say_hi()

'''运行结果:
大家好,我是菜菜,欢迎大家'''

二.类中的特殊方法

2.1构造方法

作用:在创建对象时对对象的属性进行初始化。

  • 在创建类对象(构造类)的时候,会自动执行
  • 在创建对象(构造类)的时候,将传入参数自动传递给_init_方法使用

每个类中都有一个构造方法__init__(),如果类中显式定义了构造方法,那么创建对象时调用的是显式定义的构造方法;否则调用默认的构造方法。

init()方法可以分为无参构造方法和有参构造方法

(1)使用无参构造方法创建对象时,所有对象的属性都有相同的初始值

(2)使用有参构造方法创建对象时,所有对象的属性可以有不同的初始值

【代码示例】

class Student:
    def __init__(self,name,age,tel):
        self.name = name   # 赋值的同时定义了成员变量
        self.age = age
        self.tel = tel
        print("Student类创建了一个类对象")

stu = Student("菜菜",22,"1237867826")
print(stu.name)
print(stu.age)
print(stu.tel)

'''运行结果:
Student类创建了一个类对象
菜菜
22
1237867826'''

2.2魔术方法

上面学习的__init__构造方法,是Python类内置的方法之一。这些内置的类方法,各有各的特殊功能,这些内置方法我们称之为——魔术方法

下面是几个常见的魔术方法:

在这里插入图片描述

__str__字符串方法

当类对象需要被转换成字符串之时,输出的结果是内存地址,内存地址没有多大作用,我们可以通过__str__方法,控制类转换为字符串的行为。

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    # __str__魔术方法
    def __str__(self):
        return f"Student类对象,name:{self.name},age:{self.age}"
stu = Student("菜菜",22)
print(stu)
print(str(stu))

'''运行结果:
Student类对象,name:菜菜,age:22
Student类对象,name:菜菜,age:22'''

__lt__大于小于比较方法

直接对两个对象进行比较是不可以的,但是在类中实现__lt__方法,即可同时完成:小于符号和大于符号两种比较

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    # __lt__魔术方法
    def __lt__(self,other):
        return self.age < other.age
stu1 = Student("菜菜",22)
stu2 = Student("肉肉",24)
print(stu1 < stu2)
print(stu1 > stu2)
'''运行结果:
True
False'''

__le__小于等于比较方法

__le__可用于:<=,>=两种比较运算符上

class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    # __lt__魔术方法
    def __lt__(self,other):
        return self.age < other.age
    # __le__魔术方法
    def __le__(self,other):
        return self.age <= other.age
stu1 = Student("菜菜",22)
stu2 = Student("肉肉",22)
print(stu1 <= stu2)
print(stu1 >= stu2)

'''运行结果:
True
True'''

__eq__比较运算符实现方法

  • 不实现__eq__方法,对象之间可以比较,但是比较内存地址,也就是:不同对象==比较一定是False结果
  • 实现了__eq__方法,就可以按照自己的想法来决定两个对象是否相等了
class Student:
    def __init__(self,name,age):
        self.name = name
        self.age = age
    # __eq__魔术方法
    def __eq__(self,other):
        return self.age <= other.age
stu1 = Student("菜菜",22)
stu2 = Student("肉肉",22)
print(stu1 == stu2)
'''运行结果:
True'''

三.封装

封装是面向对象的重要特征之一,它的基本思想是对外隐藏类的实现细节,提供用于访问类成员的公开接口。

为了契合封装的思想,定义类时要满足以下两点:

  1. 将属性私有化
  2. 定义两个供外界调用的公有方法,分别用于设置和获取私有属性的值。

定义私有成员:

  • 私有成员变量:变量名以__开头(两个下划线)
  • 私有成员方法:方法名以__开头(两个下划线)

使用私有成员:

在这里插入图片描述

私有成员无法被类对象使用,但是可以被其他成员使用

【代码示例】

class Phone:
    __current_voltage = 0.5
    def __keep_single_core(self):
        print("让CPU以单核模式运行")
    def call_by_5g(self):
        if self.__current_voltage >= 1:
            print("5g通话已开启")
        else:
            self.__keep_single_core()
            print("电量不足")
phone = Phone()
phone.call_by_5g()

'''运行结果:
让CPU以单核模式运行
电量不足
'''

四.继承

继承是面向对象的重要特征之一,它主要用于描述类与类之间的关系,在原有类的基础上扩展原有类的功能。如果类与类之间具有继承关系,被继承的类称为父类或基类,继承其他类的类称为子类或派生类,子类会自动拥有父类的公有成员,但不会拥有父类的私有成员,也不能访问父类的私有成员。

4.1单继承

单继承就是子类只继承一个父类,其语法格式为:

class 子类名(父类名):

【代码示例】

class Phone:
    IMEI = None
    producer = "HM"
    def call_by_4g(self):
        print("4g通话")
class Phone2022(Phone):
    face_id = "10001"
    def call_by_5g(self):
        print("2022年新功能:5g通话")
phone = Phone2022()
print(phone.producer)
phone.call_by_4g()
phone.call_by_5g()

'''运行结果:
HM
4g通话
2022年新功能:5g通话'''

4.2多继承

程序中的一个类可以继承多个类,也自动拥有所有父类的公有成员,多继承的语法格式为:

class 子类名(父类名1,父类名2...)

如果继承的多个父类中有同名的方法怎么办?

如果子类继承的多个父类是平行关系的类,那么子类先继承哪个类,就会先调用哪个类的方法。

pass关键字

是普通的占位语句,用来保证函数或者方法或者类定义法的完整性

【代码示例】

# 父类1
class Phone:
    IMEI = None
    producer = "HM"
    def call_by_4g(self):
        print("4g通话")
class Phone2022(Phone):
    face_id = "10001"
    def call_by_5g(self):
        print("2022年新功能:5g通话")
# 父类2
class NFCReader:
    nfc_type = "第五代"
    producer = "HN"
    def read_card(self):
        print("NFC读卡")
    def write_card(self):
        print("NFC写卡")
# 父类3
class RemoteControl:
    rc_type = "红外遥控"
    def control(self):
        print("红外遥控开启")
# 子类
class MyPhone(Phone,NFCReader,RemoteControl):
    pass  # 补全语法,不让语法产生错误
phone = MyPhone()
print(phone.producer)
phone.call_by_4g()
phone.read_card()
phone.write_card()
phone.control()

'''运行结果:
HM
4g通话
NFC读卡
NFC写卡
红外遥控开启'''

4.3重写

子类会原封不同地继承父类的方法,但子类有时需要按自己的需求对继承来的方法进行调整。

此时可以在子类中重写从父类继承来的方法。

python中重写父类方法的方式:在子类中定义和父类方法同名的方法,然后重新编写方法体即可。

【代码示例】

class Phone:
    IMEI = None
    producer = "ITCAST"
    def call_by_5g(self):
        print("5g通话")
class MyPhone(Phone):
    producer = "ITHEIMA"
    def call_by_5g(self):
        print("关闭5g")
phone = MyPhone()
phone.call_by_5g()
print(phone.producer)

'''运行结果:
关闭5g
ITHEIMA'''

多用父类同名成员

子类重写了从父类继承来的方法后,无法直接访问父类的同名方法,

如果需要使用被重写的父类的话,需要特殊的调用方式:

调用父类成员

使用成员变量:父亲名.成员变量

使用成员方法:父亲名.成员方法(self)

使用super()调用父类成员

使用成员变量:super().成员变量

使用成员方法:super().成员方法()

五.运算符重载

【代码示例】

class Phone:
    IMEI = None
    producer = "ITCAST"
    def call_by_5g(self):
        print("5g通话")
class MyPhone(Phone):
    producer = "ITHEIMA"
    def call_by_5g(self):
        # 方式1
        # print(f"父类的产商是:{Phone.producer}")
        # Phone.call_by_5g(self)
        # 方式2
        print(f"父类的产商是:{super().producer}")
        super().call_by_5g()
        print("关闭5g")
phone = MyPhone()
phone.call_by_5g()
print(phone.producer)

'''运行结果:
父类的产商是:ITCAST
5g通话
关闭5g
ITHEIMA'''

六.类型注解

在这里插入图片描述

在代码中涉及数据交互的地方,提供数据类型的注解(显式的说明)

主要功能:

  • 帮助第三方IDE工具(如PyCharm)对代码进行类型推断,协助做代码提示
  • 帮助开发者自身对变量进行类型注释

支持:

  • 变量的类型注解
  • 函数(方法)形参列表和返回值的类型注解

6.1变量的类型注解

【语法】:变量:类型

在这里插入图片描述

在这里插入图片描述

除了使用上述方法做注解外,也可以在注释中进行类型注解

【语法】:# type:类型

在这里插入图片描述

注意:类型注解仅仅是提示性的,不是决定性的。数据类型和注解类型也不会导致错误。

6.2函数(方法)的类型注解

在这里插入图片描述

【语法】:

def 函数方法名(形参名:类型,形参名:类型,....):
    pass

对返回值进行注解

def 函数方法名(形参名:类型,形参名:类型,....)->返回值类型:
    pass

6.3Union类型

使用Union可以定义联合类型注解

Union的使用方式:

  • 导包:from typing import Union
  • 使用:Union[类型,....,类型]

在这里插入图片描述

同样,union也可以给函数做注解->

在这里插入图片描述

七.多态

多态是面向对象的重要特征,它的表现形式是:让不同类的同一方法,可以通过相同的接口调用,表现出不同的行为。

在这里插入图片描述

例如:定义一个Cat类和一个Dog类,两个类中都定义shout()方法:

class Cat:
    def shout(self):
        print("喵喵")
class Dog:
    def shout(self):
        print("汪汪")
 
#定义一个接口,通过这个接口调用Cat类和Dog类中的shout()方法
def shout(obj):
    obj.shout()
 
cat = Cat()
dog = Dog()
shout(cat)
shout(dog)

在函数shout(obj)中,参数obj代表一个对象,可以是Cat类的实例,也可以是Dog类的实例,甚至是其他类的实例。通过传递不同的对象给shout(obj)函数,可以实现对不同类中相同名称方法的调用。

利用多态这一特性编写代码不会影响类的内部设计,但可以提高代码的兼容性,让代码的调度更加灵活。

可见,父类Animal的shout方法,是空实现:

在这里插入图片描述

八.抽象类(接口)

抽象类就好比定义一个标准

包含了一些抽象的方法,要求子类必须实现。自己没有具体的实现方法。

在这里插入图片描述


http://www.kler.cn/a/515226.html

相关文章:

  • [STM32 HAL库]串口中断编程思路
  • SQL-leetcode—1164. 指定日期的产品价格
  • wordpress付费查看隐藏内容插件的开发演示和记录
  • 爬虫基础之爬取某站视频
  • C++语言的区块链
  • 国产编辑器EverEdit - 列编辑模式
  • 修改word的作者 最后一次保存者 总编辑时间 创建时间 最后一次保存的日期
  • 白玉微瑕:闲谈 SwiftUI 过渡(Transition)动画的“口是心非”(下)
  • 无人机 PX4 飞控 | PX4源码添加自定义参数方法并用QGC显示与调整
  • 使用EVE-NG-锐捷实现静态路由
  • jvm_threads_live_threads 和 jvm_threads_states_threads 这两个指标之间存在一定的关系,但它们关注的维度不同
  • 【Go面试】工作经验篇 (持续整合)
  • 通俗的讲,网络爬虫到底是什么?
  • HQChart使用教程30-K线图如何对接第3方数据45- DRAWRADAR数据结构
  • jvm G1 垃圾收集日志分析示例(GC)
  • ubuntu终端当一段时间内没有程序运行时,自动关闭终端。
  • Golang笔记—— error 和 panic
  • 在 Ubuntu 22.04 上安装 Kubernetes(Kubeadm 安装方式)
  • STM32 ST7735 128*160
  • 数据链路层协议
  • FluentCMS:基于 ASP.NET Core 和 Blazor 技术构建的开源CMS内容管理系统
  • 代码随想录——串
  • mysql 性能调优之连接配置优化
  • 26岁备考PMP,经验分享
  • 支持selenium的chrome driver更新到132.0.6834.83
  • 嵌入式知识体系分析+数据结构概念+时间复杂度计算规则+顺序表的原理与实现