深入了解 Python 面向对象编程(最终篇)

news2024/9/9 5:40:19

大家好!今天我们将继续探讨 Python 中的类及其在面向对象编程(OOP)中的应用。面向对象编程是一种编程范式,它使用“对象”来模拟现实世界的事务,使代码更加结构化和易于维护。在上一篇文章中,我们详细了解了类和实例的概念、' self ' 关键字的作用、魔法函数的定义、构造函数和析构函数以及面向对象编程的三大特性、抽象类、动态添加内容。而今天,我们将会在原有的基础上学习:数据的三种类型、属性封装以及单例类,让我们开始吧!

一、面向对象编程(OOP)

面向对象编程是一种将现实世界事务使用类与实例来模拟的方法。在 OOP 中,所有事物都被视为对象。这些对象可以是具体的,如:

灯:可以开关的设备。
汽车:具有属性(如颜色、品牌)和行为(如行驶、停车)的交通工具。
导弹:具备特定属性和发射行为的武器。
杯子:用于盛放液体的容器。

通过将这些现实世界的事务抽象为对象,我们可以创建更易于理解和操作的代码结构。

二、类与实例

1. 类
类是对现实世界描述的一种类型。它是一个抽象的概念,约定了未来实例应该有的内容。定义类的基本语法如下:

class 类名:
    pass

在 Python 中,类名通常采用大驼峰(Pascal Case)命名法。

例如,我们可以定义一个名为' Car '  的类:

class Car:
    pass

类是实例的模板,它定义了实例的属性和行为,但并不包含具体的数据。

2. 实例
实例是通过调用类生成的具体对象。生成实例的语法为:

实例名 = 类名()

例如:

my_car = Car()

这里,' my_car ' 是  ' Car ' 类的一个实例,它包含了  ' Car ' 类定义的所有属性和方法,但具体的数据是属于这个实例的。

三、' self ' 关键字


' self ' 关键字在类的方法内部,' self ' 代表实例本身。它用于访问实例的属性和方法。' self ' 必须作为第一个参数出现在类的方法中。让我们看一个简单的例子,展示如何使用 ' self ' :

class Dog:
    def __init__(self, name):
        self.name = name  # 将实例属性name初始化为传入的name参数
 
    def bark(self):
        return f"{self.name} says Woof!"
在上面的代码中,' __init__ ' 是一个初始化函数,用于创建实例时初始化属性。通过 ' self ' ,我们可以在 ' bark ' 方法中引用实例的 ' name ' 属性。

四、魔法函数


魔法函数是以双下划线开头和结尾的特殊方法,它们能够实现某些特定的功能。常用的魔法函数包括:

1. 初始化与字符串表示
 ' __init__(self) ' :构造函数,用于初始化实例。
 ' __str__(self) ' :定义对象的字符串表示,通常用于 ' print() ' 函数。

class Cat:
    def __init__(self, name):
        self.name = name
 
    def __str__(self):
        return f"This is {self.name} the cat."

2. 长度与比较
' __len__(self) ' :返回对象的长度。
比较运算符魔法函数:                                                                                                                       ' __eq__(self, other) ':等于比较。
 ' __ne__(self, other) ':不等于比较。
 ' __gt__(self, other) ':大于比较。
 ' __ge__(self, other) ':大于或等于比较。
 ' __lt__(self, other) ':小于比较。
 ' __le__(self, other) ':小于或等于比较。

class Box:
    def __init__(self, size):
        self.size = size
 
    def __len__(self):
        return self.size
 
    def __eq__(self, other):
        return self.size == other.size

3. 算术运算
魔法函数还可以重载算术运算符,使得我们能够使用常见的运算符(如 `+`、`-` 等)对自定义对象进行操作。这些魔法函数包括:

' __add__(self, other) ' :实现加法运算。
' __sub__(self, other) ':实现减法运算。
' __mul__(self, other) ':实现乘法运算。
' __truediv__(self, other) ':实现除法运算。
' __mod__(self, other) ':实现取模运算。以下是一个示例,展示如何使用 ' __add__ ' 魔法函数:

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y
 
    def __add__(self, other):
        return Point(self.x + other.x, self.y + other.y)
 
    def __repr__(self):
        return f"Point({self.x}, {self.y})"
 
# 创建两个 Point 实例
p1 = Point(1, 2)
p2 = Point(3, 4)
p3 = p1 + p2  # 这里会调用 p1.__add__(p2)
print(p3)  # 输出: Point(4, 6)

在这个例子中,' __add__ ' 方法允许我们直接使用 ' + ' 运算符来相加两个 ' Point ' 实例。

五、构造函数与析构函数

1. 初始化函数
初始化函数是一个特殊的方法,用于初始化实例的属性。' __init__ ' 方法在创建对象时自动调用。

class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age
 
    def display(self):
        return f"姓名: {self.name}, 年龄: {self.age}"
 
# 创建实例
person = Person("Alice", 30)
print(person.display())  # 输出: 姓名: Alice, 年龄: 30

2. 构造函数
构造函数是一个特殊的方法,用于创建实例。' __new__ ' 方法在实例被创建时被调用。通常情况下,我们不需要直接使用 ' __new__ ' ,但在需要控制实例创建过程时可以使用。

class Singleton:
    _instance = None
 
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance
 
# 测试 Singleton 类
s1 = Singleton()
s2 = Singleton()
 
print(s1 is s2)  # 输出: True,确保只有一个实例

3. 析构函数
析构函数是另一个特殊的方法,在实例不再使用时被调用,通常用于释放资源。Python 中的析构函数是 ' __del__ ' 方法。虽然 Python 有垃圾回收机制,但在某些情况下,手动释放资源是很有用的。

析构函数的基本结构如下:

def __del__(self):
    # 清理代码

 下面是一个简单的示例,展示如何使用析构函数:

class Resource:
    def __init__(self):
        print("Resource acquired!")
 
    def __del__(self):
        print("Resource released!")
 
# 创建一个资源对象
res = Resource()
# 资源会在对象销毁时被释放

当 ' res ' 对象超出作用域时,Python 的垃圾回收会调用 ' __del__ ' 方法,输出“Resource released!”。

六、面向对象编程的三大特性


在 OOP 中,有三大基本特性:封装、继承和多态。

1. 封装
封装是指将数据和方法结合在一起,并限制对某些数据的直接访问。通过封装,我们可以保护对象的内部状态,只通过公共方法(接口)来访问和修改这些状态。

class Person:
    def __init__(self, name, age):
        self.__name = name  # 私有属性
        self.__age = age    # 私有属性
 
    def get_name(self):
        return self.__name
 
    def set_name(self, name):
        self.__name = name
 
    def get_age(self):
        return self.__age
 
    def set_age(self, age):
        if age > 0:
            self.__age = age
        else:
            print("年龄必须为正数!")
 
# 创建实例
person = Person("Alice", 30)
print(person.get_name())  # 输出: Alice
person.set_age(-5)        # 输出: 年龄必须为正数!

在上面的代码中,我们使用了双下划线 ' __ ' 将实例属性  ' __name '  和 ' __age ' 定义为私有属性,这样它们就不能被直接访问。我们提供了公共方法 ' get_name ' 和  ' set_name ' 来访问和修改这些私有属性。这种封装机制不仅保护了对象的内部状态,还提供了更好的数据验证和控制。

2. 继承
继承是指一个类(子类)可以继承另一个类(父类)的属性和方法,从而实现代码的重用。子类可以扩展或修改父类的行为。

class Animal:
    def speak(self):
        return "Animal speaks"
 
class Dog(Animal):  # Dog 继承自 Animal
    def speak(self):
        return "Woof!"
 
class Cat(Animal):  # Cat 也继承自 Animal
    def speak(self):
        return "Meow!"
 
# 实例化对象
dog = Dog()
cat = Cat()
print(dog.speak())  # 输出: Woof!
print(cat.speak())  # 输出: Meow!

在这个例子中,' Dog ' 和 ' Cat ' 类都继承了 ' Animal ' 类的 ' speak ' 方法,但它们各自实现了自己的版本。这种特性使得我们可以创建一个通用的父类,并根据需要扩展子类。

多重继承
Python 支持多重继承,即一个类可以同时继承多个类。这在某些情况下非常有用,但也可能导致复杂性(如菱形继承问题)。

class Flyer:
    def fly(self):
        return "Flying"
 
class Swimmer:
    def swim(self):
        return "Swimming"
 
class Duck(Flyer, Swimmer):
    def quack(self):
        return "Quack!"
 
# 实例化 Duck
duck = Duck()
print(duck.fly())  # 输出: Flying
print(duck.swim())  # 输出: Swimming
print(duck.quack())  # 输出: Quack!

3. 多态
多态是指不同类的对象可以通过相同的接口进行操作。多态的实现通常依赖于继承和方法重载。Python 中的多态通常有两种形式:

1. 方法重载(函数同名不同参数)
Python 不支持传统意义上的方法重载,但我们可以使用可变参数( ' *args ' 和 ' **kwargs ' )来实现类似效果。

class MathOperation:
    def add(self, *args):
        return sum(args)
 
math_op = MathOperation()
print(math_op.add(1, 2))          # 输出: 3
print(math_op.add(1, 2, 3, 4, 5))  # 输出: 15

2. 父子类多态
父类和子类的方法名相同,但实现不同。我们可以通过多态来处理不同类型的对象。

def animal_sound(animal):
    print(animal.speak())
 
# 实例化对象
dog = Dog()
cat = Cat()
animal_sound(dog)  # 输出: Woof!
animal_sound(cat)  # 输出: Meow!

在这个例子中,' animal_sound ' 函数接收 ' Animal ' 类型的对象,不论是 ' Dog ' 还是 ' Cat ',都可以调用 ' speak ' 方法。

七、抽象类

抽象类是一种特殊的类,用于定义接口并强制子类实现特定的方法。抽象类不能被实例化,通常用于提供一个模板,要求其子类实现抽象方法。使用 `abc` 模块来定义抽象类和抽象方法。

from abc import ABC, abstractmethod

class Animal(ABC):  # 继承自 ABC,表示这是一个抽象类
    @abstractmethod
    def speak(self):  # 抽象方法
        pass

class Dog(Animal):
    def speak(self):
        return "Woof!"

class Cat(Animal):
    def speak(self):
        return "Meow!"

# 实例化对象
dog = Dog()
cat = Cat()
print(dog.speak())  # 输出: Woof!
print(cat.speak())  # 输出: Meow!

# animal = Animal()  # 这将引发错误,因为不能实例化抽象类

在这个示例中,' Animal ' 是一个抽象类,定义了一个抽象方法 ' speak ' 。子类 ' Dog ' 和 ' Cat ' 必须实现这个方法,否则会引发错误。抽象类的使用使得接口的实现变得一致,并确保所有子类都具备特定的方法。

八、动态添加内容

Python 是一门动态语言,允许我们在运行时向类和实例添加属性和方法。这种灵活性使得 Python 在许多场景下非常强大。

1. 添加实例属性我们可以在实例创建后直接为实例添加新的属性。
 

class Cup:
    def __init__(self, capacity):
        self.capacity = capacity

# 创建实例
my_cup = Cup(300)
my_cup.color = "Blue"  # 动态添加实例属性
print(my_cup.color)  # 输出: Blue

在这个例子中,我们创建了一个 ' Cup ' 类的实例 ' my_cup ' ,然后动态地为其添加了一个'color' 属性。

2. 添加实例方法

可以使用 ' types.MethodType ' 动态添加实例方法。注意,动态添加的方法的第一个参数必须是 ' self '。

import types

def new_method(self):
    return f"This cup has a capacity of {self.capacity} ml."

my_cup.new_method = types.MethodType(new_method, my_cup)  # 动态添加实例方法
print(my_cup.new_method())  # 输出: This cup has a capacity of 300 ml.

在这个例子中,我们定义了一个新的方法 ' new_method ' ,然后使用 ' types.MethodType ' 将其动态添加到 ' my_cup ' 实例中。

3. 添加类属性和方法

同样地,我们可以向类本身动态添加属性和方法。

Cup.color = "Red"  # 动态添加类属性
print(Cup.color)  # 输出: Red

def class_method(cls):
    return f"This class has the capacity: {cls.color}"

Cup.class_method = classmethod(class_method)  # 动态添加类方法
print(Cup.class_method())  # 输出: This class has the capacity: Red

在这个例子中,我们为 ' Cup ' 类添加了一个类属性 ' color ' 和一个类方法 ' class_method ',并可以通过类名直接访问它们。

九、数据的访问级别

在 Python 中,属性和方法可以有不同的访问级别,主要分为公有、私有和保护类型。

1. 公有类型

公有属性和方法是最常见的,普通命名方式可以在类内和类外被直接访问。

class PublicExample:
    def __init__(self):
        self.public_value = "I am public!"

example = PublicExample()
print(example.public_value)  # 输出: I am public!

2. 私有类型

私有属性和方法以 ' __ ' 开头,只能在类内访问,外部无法直接访问。这种机制用于保护类的内部实现。

class PrivateExample:
    def __init__(self):
        self.__private_value = "I am private!"

    def get_private_value(self):
        return self.__private_value

example = PrivateExample()
print(example.get_private_value())  # 输出: I am private!
# print(example.__private_value)  # 会引发 AttributeError

3. 保护类型

保护属性和方法以 ' _ ' 开头,可以在类内和子类中访问,但在类外不能直接访问。这是一种建议性约定,表示属性不应被外部直接访问。
 

class ProtectedExample:
    def __init__(self):
        self._protected_value = "I am protected!"

example = ProtectedExample()
print(example._protected_value)  # 输出: I am protected!

十、属性封装

属性封装是指通过 ' property ' 装饰器来控制对属性的访问。这种机制允许我们在获取或设置属性时添加逻辑。

1. 使用 ' property '

 通过 ' property ' 装饰器,我们可以定义 getter 和 setter 方法,从而控制对属性的访问。

class Person:
    def __init__(self, name, age):
        self.__name = name
        self.__age = age

    @property
    def name(self):
        return self.__name

    @name.setter
    def name(self, name):
        self.__name = name

    @property
    def age(self):
        return self.__age

    @age.setter
    def age(self, age):
        if age > 0:
            self.__age = age
        else:
            print("年龄必须为正数!")

# 创建实例
person = Person("Alice", 30)
print(person.name)  # 输出: Alice
person.age = -5    # 输出: 年龄必须为正数!

在这个示例中,我们通过 ' @property ' 装饰器为 ' name ' 和 ' age '  属性定义了访问和设置方法,从而实现了属性的封装和数据验证。

十一、单例类


单例类是一种设计模式,确保一个类只有一个实例,并提供一个全局访问点。实现单例模式的常用方法是控制类的构造函数,确保在第一次创建实例时生成,并在后续请求时返回该实例。

class Singleton:
    _instance = None

    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(Singleton, cls).__new__(cls)
        return cls._instance

# 测试 Singleton 类
s1 = Singleton()
s2 = Singleton()

print(s1 is s2)  # 输出: True,确保只有一个实例

在这个示例中,' Singleton ' 类的 ' __new__ ' 方法确保在第一次请求实例时创建一个新对象,而后续请求则返回这个对象。这样,' s1 ' 和 ' s2 ' 是同一个实例。

十二、总结

通过本篇文章,我们深入了解了 Python 中的类和面向对象编程的基本概念,包括:

1.类与实例:类是对象的模板,实例是具体的对象。类定义了属性和行为,实例则包含具体的数据。
2. ' self ' 关键字:用于引用实例本身,允许在方法中访问实例属性和方法。
3. 魔法函数:特殊的方法,允许我们定义对象的行为(如初始化、比较和运算),包括     '__init__ '、' __str__ ' 、' __len__ ' 等。
4.构造函数与析构函数:用于创建和销毁实例,管理资源。构造函数 ' __new__ ' 和析构函数 '__del__' 使得我们可以控制实例的创建和销毁过程。
5. 面向对象编程的三大特性:
   封装:将数据和方法结合在一起,保护对象的内部状态。
   继承:允许子类继承父类的属性和方法,促进代码重用。
   多态:允许不同类的对象通过相同的接口进行操作,提高代码的灵活性和可扩展性。
6. 抽象类:用于定义接口,强制子类实现特定的方法,提供一致性。
7. 动态添加内容:Python 允许在运行时向类和实例添加属性和方法,增加了编程的灵活性。
8.数据的访问级别:Python 提供公有、私有和保护类型来控制属性的访问。
9. 属性封装:通过 `property` 装饰器控制对属性的访问和修改。
10. 单例模式:确保一个类只有一个实例,并提供全局访问点。

面向对象编程的优势在于它将数据和功能封装在一起,使代码更加模块化、可读且易于维护。这种结构不仅有助于我们更好地组织代码,还能提高开发效率。

希望通过本篇文章,您对 Python 的面向对象编程有了更深入的了解!如果您有任何问题或想进一步讨论的内容,请随时在评论区留言。感谢您的阅读,我们下次再见!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1961733.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RocketMQ Server Windows安装

RocketMQ阿里开发 开源给apache 官网:RocketMQ 官方网站 | RocketMQ 下载后解压 配置环境变量 注意启动顺序 双击 注意 4.9.0这个版本必须 jdk 8 高了用不了 namesrv是注册中心的作用 broke是核心用于接收生产者消息 存储消息 发送给消费者消息 类似DubboZookeeper…

C++ 绘制画布标尺

目标 关键代码 CRulerDrawer::CRulerDrawer(QPainter& painter, QRect rect, int scalePercent): m_painter(painter), m_rect(rect), m_scalePercent(scalePercent) {m_palette qApp->palette();m_scaleUnitSize PixelRuler::Instance()->GetScaleUnitSize(); }vo…

【JS|第22期】深入理解跨域

日期:2024年7月6日 作者:Commas 签名:(ง •_•)ง 积跬步以致千里,积小流以成江海…… 注释:如果您觉得有所帮助,帮忙点个赞,也可以关注我,我们一起成长;如果有不对的地方&#xff…

Vue开发环境搭建

文章目录 引言I 安装NVM1.1 Windows系统安装NVM,实现Node.js多版本管理1.2 配置下载镜像1.3 NVM常用操作命令II VUE项目的基础配置2.1 制定不同的环境配置2.2 正式环境隐藏日志2.3 vscode常用插件引言 开发工具: node.js 、npm 开发编辑器:vscode 开发框架:VUE I 安装NVM…

react中zuStand状态管理工具使用

一、zuStand的基本使用 1.安装工具 npm install zustand 2.新建文件 在src下新建store文件夹,在store文件夹下新建zuStand.js文件 3.配置zuStand.js // 1.引入创建方法 import { create } from "zustand";// 2.创建store const useStore create((s…

未来不会使用 AI 的人真的会被淘汰吗?

AI 是今年大火的一个话题,随着 ChatGPT 之类的一系列大模型开始流行以后,有不少的培训机构宣称这样的口号: “未来不会使用 AI 的人将会被淘汰”。我觉得这个观点本身并没有错,但是关键在于那些培训机构出于自身的利益,故意忽略了…

(源码分析)springsecurity认证授权

了解 1. 结构总览 SpringSecurity所解决的问题就是安全访问控制,而安全访问控制功能其实就是对所有进入系统的请求进行拦截,校验每个请求是否能够访问它所期望的资源。 根据前边知识的学习,可以通过Filter或AoP等技术来实现,Spr…

Sparse Vector Coding稀疏矢量码介绍

需要MATLAB代码的小伙伴请通过微信公众号私信我~ 更多精彩内容请关注微信公众号 ‘优化与算法’ 前言 5G和6G无线通信期望带来更高的频谱效率和能量效率,为了达到这些目标,近年来已经提出了各种新技术。其中,索引调制IM(Index …

「树形结构」基于 Antd 实现一个动态增加子节点+可拖拽的树

效果 如图所示 实现 import { createRoot } from react-dom/client; import React, { useState } from react; import { Tree, Input, Button } from antd; import { PlusOutlined } from ant-design/icons;const { TreeNode } Tree; const { Search } Input;const ini…

优选算法之位运算

目录 一、常见位运算总结 1.基础位运算 2.给定一个数 n,确定它的二进制表示中的第 x 位是 0 还是 1 3.将一个数 n 的二进制表示的第 x 位修改成1 4.将一个数 n 的二进制表示的第 x 位修改成 0 5.提取一个数 n 二进制表示中最右侧的1 6.干掉一个数 n 二进制表示…

分布式存储系统架构及应用

分布式存储系统概述(详细、全面) 【摘要】深度剖析分布式存储系统的可靠性、可用性、IO性能、数据存储效率、安全性及管理性,为寻求了解此领域的读者提供实用参考。 一、 内容总括 分布式存储系统,依托网络互联的多节点软硬件协同…

人脸识别又进化:扫一下 我就知道你得了啥病

未来,扫下你的脸,可能就知道你得啥病了。没在瞎掰,最近的一项研究成果,还真让咱看到了一点眉目。北大的一个研究团队,搞出来一个 AI ,说是用热成像仪扫一下脸,就能检测出有没有高血压、糖尿病和…

工作纪实54-git使用ssh方式

很多居家的小伙伴要重新clone项目,但是忘记了密码,最恶心的是idea还会自动帮你记录密码,如果输错了,会很恶心,使用ssh则不会;还有一个好处就是,集团的密码一般都是几个月更新一次,ss…

基于Frp搭建Window-Linux内网穿透完整流程

什么是内网穿透? 内网穿透是我们在进行网络连接时的一种术语,也叫做NAT穿透,即在计算机是局域网内的时候,外网与内网的计算机的节点进行连接时所需要的连接通信,有时候就会出现内网穿透不支的情况。内网穿透的功能就是&#xff0…

只出现一次的数字-位运算

题目描述&#xff1a; 个人题解&#xff1a; 代码实现&#xff1a; class Solution { public:int singleNumber(vector<int>& nums) {int ret 0;for (auto e: nums) ret ^ e;return ret;} };复杂度分析&#xff1a; 时间复杂度&#xff1a;O(n)&#xff0c;其中 n…

19018 正则序列

这个问题可以通过排序和计数来解决。首先&#xff0c;我们将数组排序&#xff0c;然后我们遍历排序后的数组&#xff0c;对于每个元素&#xff0c;我们将它变为它应该在正则序列中的值&#xff0c;也就是它的索引加1。我们将这个变化的绝对值累加起来&#xff0c;这就是我们需要…

STM32智能农业灌溉系统教程

目录 引言环境准备智能农业灌溉系统基础代码实现&#xff1a;实现智能农业灌溉系统 4.1 数据采集模块 4.2 数据处理与分析模块 4.3 通信与网络系统实现 4.4 用户界面与数据可视化应用场景&#xff1a;农业监测与优化问题解决方案与优化收尾与总结 1. 引言 智能农业灌溉系统通…

Sklearn实例:水果多分类

机器学习五步&#xff1a; 加载数据集分割数据集建立模型训练模型预测模型 导入库文件 import numpy as np #科学计算库 import matplotlib.pyplot as plt #绘图库可视化函数 import pandas as pd #数据处理库&#xff0c;数据分析库 import seaborn as sns #高级数据可视化…

AI技术修复奥运珍贵历史影像,《永不失色的她》再现百年奥运女性光彩

Greatness of HER &#xff01; AI致敬 , 了不起的「她」。 7月25日&#xff0c;在国际奥委会和各方力量的支持下&#xff0c;阿里云以AI技术修复奥运珍贵历史影像&#xff0c;让百年奥运女性的伟大光彩被看见&#xff0c;并在巴黎推出《永不失色的她》全球首映礼。 国际奥委会…