16. 面向对象编程

一、什么是面向对象

  对象(Object)是内存中专门用来存储数据的一块区域。对象中可以存放各种数据,比如:数字、布尔值、代码等。对象由 对象的标识(id)、对象的类型(type)和 对象的值(value)三部分组成。

  Python 是一门面向对象的编程语言。所谓的 面向对象 的语言,简单理解就是语言中所有操作都是通过对象来进行的。面向对象的编程语言,关注的是对象,而不关注过程。它将功能封装进对象,强调具备了功能的对象,以类/对象为最小单位,考虑谁来做。如果要使用某个功能,直接找到对应的对象即可。对于面向对象的语言来说,一切都是对象。面向对象 为单位,每种事物都具备自己的 属性方法/功能。面向对象这种方式编写的代码,可读性比较高,并且易于维护,可复用性比较高。但是这种方式,不太符合常规的思维,编写起来稍微麻烦一点。

  与之对应的就是 面向过程 的编程语言,面向过程的编程语言指将我们的程序的逻辑分解为一个一个的步骤,通过对每个步骤的抽象,来完成程序。但是这种编写的代码往往只适用于一个功能。如果要实现别的功能,即使功能相差极小,也往往需要重新编写代码,所以它的可复用性比较低,并且难以维护。面向过程 强调的是 功能行为,以 函数 为最小单位,考虑怎么做;这种编程方式,符合我们人类思维,编写起来相对简单。

  面向过程其实是最为实际的一种思考方式,就算是面向对象的方法也是含有面向过程的思想。可以说面向过程是一种基础的方法。它考虑的是实际地执行。一般的面向过程是从上往下步步求精。面向对象主要是把事物给对象化,对象包括属性与行为。当程序规模不是很大的时候,面向过程的方法还会体现出一种优势。因为程序的流程很清楚,按着模块与函数的方法可以很好的组织。但对于复杂而庞大的系统来说,面向过程显着就很无力了。

二、类与对象

  (Class)和 对象(Object)是面向对象的核心概念。 是对一类事物的描述,是 抽象的、概念上的定义,简单理解就相当于一个图纸;对象 是实际存在的该类事物的每个个体,是 具体的,因此也称为 实例(instance);在程序中我们根据类来创建对象。我们也称对象是类的实例。如果多个对象是通过一个类创建的,我们称这些对象是一类对象。

  面向对象程序设计的重点是 类的设计,类的设计,其实就是 类的成员的设计

  1. 创建类,设计类的内部成员(属性、方法)
  2. 创建类的对象
  3. 通过对象,调用其内部声明的属性或方法,完成相关的功能
class Person():passprint(Person)
print(id(Person))
print(type(Person), '\n')# 使用类创建对象
p1 = Person()
print(p1)
print(type(p1),'\n')p2 = Person()
p2.name = "Sakura"
print(p2.name,'\n')name = str("Sakura")
# 我们可以用isinstance()用来检查一个对象是否是一类类的实例
print(isinstance(p1, Person))
print(isinstance(p2, Person))
print(isinstance(name, Person))

类也是一个对象,类是创建对象的对象;

类是 type 类型的对象,定义类实际上就是定义了一个 type 类型的对象;

三、类的成员

3.1、属性

  属性 用来描述具体某个对象的特征。描述的是对象的状态信息,通常以变量的形式进行定义。在类中我们定义的变量,将会成为所有实例的公共属性,所有实例都可以通过 对象.属性名 的方式访问这些变量。

  直接在类中定义的属性是 类属性,类属性可以通过类或类的实例访问到,但是类属性只能通过类对象来修改,无法通过实例对象修改。我们还可以创建的实例中动态的添加属性,这种属性属于 实例属性。实例属性只能通过实例对象来访问和修改,类对象无法访问修改。

  当我们调用一个对象时,解析器会先在当前对象中寻找是否含有该属性,如果有则直接返回当前对象的属性值,如果没有则去当前对象的类对象中去寻找,如果有则返回类对象的属性值,如果没有则报错。

class Person:# 类属性,直接在类中定义的属性name = "Unknown"# 类属性可以通过类或类的实例访问到
p1 = Person()
print("Person: ", Person.name)
print("p1", p1.name, '\n')# 类属性只能通过类对象来修改,无法通过实例对象修改
Person.name = "Sakura"
print("Person: ", Person.name)
print("p1", p1.name, '\n')# 通过实例对象添加的属性属于实例属性
# 实例属性只能通过实例对象来访问和修改,类对象无法访问修改
p2 = Person()
p2.name = "Mikoto"
print("Person: ", Person.name)
print("p2: ", p2.name, '\n')del p2.name
print(p2.name)

  类对象和实例对象都可以保存属性,如果这个属性是所有的实例共享的,则应该将其保存到类对象中。如果这个属性是某个实例独有的,则应该保存到实例对象中。一般情况下,属性保存在实例对象中。

class Person:# 类属性,直接在类中定义的属性name = "Unknown"p1 = Person()
p2 = Person()print(id(Person.name))
print(id(p1.name))
print(id(p2.name))

3.2、方法

  方法 是类或对象行为特征的抽象,用来完成某个功能的操作。在其它编程语言中,方法 也被称为 函数过程。在类中定义的函数,将会成为所有实例的公共方法,所有该类实例都可以通过 对象.方法名() 的形式调用方法。在实际开发中,我们可以将重复的代码、具有独立功能的代码抽取到方法中。使用方法后,我们可以提高代码的复用性和可维护性。

3.2.1、实例方法

  实例方法 每次调用时,解析器都会自动传递第一个实参,这个参数就是调用方法的 对象本身,一般我们都会将这个参数命名为 self。实例方法通过对象调用时,会自动将当前对象作为 self 传入,实例方法通过类调用时,不会自动传递 self,必须我们手动传递 self。

class Person:# 实例方法每次调用时,解析器都会自动传递第一个实参# 实例方法的第一个参数就是调用方法的对象本身,一般我们都会将这个参数命名为selfdef say_hello(self):print(self)# 在方法中不能直接访问实例对象的属性print("你好,我是 %s" %self.name)p1 = Person()
print(p1,'\n')p1.name = "Sakura"
# 实例方法通过类调用时,会自动将当前对象作为self传入
p1.say_hello()
# 实例方法通过类调用时,不会自动传递self,必须我们手动传递self
Person.say_hello(p1)
print()p2 = Person()
print(p2,'\n')p2.name = "Mikoto"
p2.say_hello()

注意:方法调用时,解析器会把当前对象当作第一个参数自动传递,所以定义实例方法时,至少定义一个形参;

3.2.2、类方法

  在类内部使用 @classmethod 来修饰的方法属于 类方法, 类方法的第一个参数就是当前的 类对象,一般我们都会将这个参数命名为 cls。类方法可以通过类调用,也可以通过实例调用。

class Person:# 类属性count = 0# 在类内部使用@classmethod来修饰的方法属于类方法# 类方法的第一个参数就是当前的类对象,一般我们都会将这个参数命名为cls@classmethoddef showInfo(cls):print(cls)print("我的身份编号为:",cls.count)p1 = Person()
# 类方法可以通过类调用
Person.showInfo()
# 类方法也可以通过实例调用
p1.showInfo()

注意:方法调用时,解析器会把当前类对象当作第一个参数自动传递,所以定义实例方法时,至少定义一个形参;

3.2.3、静态方法

  在类中使用 @staticmethod 来修饰的方法属于 静态方法,静态方法不需要指定任何的默认参数。静态方法,基本上是一个和方法无关的方法,它只是保存到当前类中的函数,静态方法一般都是一些工具方法,和当前类无关。

class Person:# 在类中使用@staticmethod来修饰的方法属于静态方法# 静态方法不需要指定任何的默认参数@staticmethoddef show():print("我是一个人")p1 = Person()# 静态方法可以通过类或实例取调用
Person.show()
p1.show()

3.3、魔法属性

__doc__             # 查看类的描述信息
__module__          # 查看当前操作的对象在哪个模块
__class__           # 表示当前操作的对象的类是什么
__dict__            # 类或对象中的所有属性
class Person:"""人的描述类"""name = "unknown"def show_info(self):print(f"我是一个人,名字是: {self.name}")p = Person()
p.name = "Sakura"
p.age = 10print(f"p.doc: {p.__doc__}")
print(f"p.module: {p.__module__}")
print(f"p.class: {p.__class__}")
print(f"Person.dict: {Person.__dict__}")
print(f"p.dict: {p.__dict__}")

Python 解释器会将对象(类对象、实例对象)中的所有属性、方法,统统用字典存储,将属性的名字变为字典的 key,将属性对应的数据当做字典中的 value。将方法的名字变为字典中的 key,将方法所对应的引用当做字典中的 value;

3.4、魔法方法

  在类中可以定义一些特殊方法(魔法方法),特殊方法都是以双下划线 __ 开头,双下划线 __ 结尾。特殊方法不需要我们自己调用,它会在特殊的时候自动调用。

  __init__() 会在创建对象后立即执行,它可以用来向新创建的对象初始化属性。

object.__init__(self[, ...])
class Person:# __init__(self)会在对象创建后立即执行# __init__(self)可以用来向新创建的对象初始化属性def __init__(self, name, age):# 通过self向新创建堆额对象中初始化属性self.name = nameself.age = agedef showInfo(self):# 在方法中不能直接访问实例对象的属性print("你好,我是 %s,我今年 %d 岁。" %(self.name,self.age))# 调用类创建对象是,类后面的所有参数都会一次传递给__init__(self)中
p1 = Person("Sakura",10)
p1.showInfo()p2 = Person("Mikoto",14)
p2.showInfo()

__init()__ 方法必须返回 None;

  __new__() 这个特殊方法会在创建类时自动调用。

object.__new__(cls[, ...])
class Person:# __new__(cls)这个特殊方法会在创建类时自动调用def __new__(cls):print("__new__(cls)执行了")print(cls)# 调用类创建对象是,类后面的所有参数都会一次传递给__init__(self)中
p1 = Person()

  __del__() 这个特殊方法会在对象删除前调用。

object.__del__(self)
class Person:# __init__(self)会在对象创建后立即执行# __init__(self)可以用来向新创建的对象初始化属性def __init__(self, name, age):# 通过self向新创建堆额对象中初始化属性self.name = nameself.age = age# __del__(self)会在对象删除前调用def __del__(self):print("del(self)方法执行了")print(self.name,"被删除了")# 调用类创建对象是,类后面的所有参数都会一次传递给__init__(self)中
p1 = Person("Sakura",10)
p1 = Nonep2 = Person("Mikoto",14)

  __call__() 会在对象加括号后自动执行。

object.__call__(self[, args...])
class Person:def __call__(self):print("call方法被执行了")# 调用类创建对象是,类后面的所有参数都会一次传递给__init__(self)中
p1 = Person()
p1()

  __str__() 会在当前对象转换为字符串时使用,它可以用来指定对象转换为字符串的结果。

object.__str__(self)
class Person:# __init__(self)会在对象创建后立即执行# __init__(self)可以用来向新创建的对象初始化属性def __init__(self, name, age):# 通过self向新创建堆额对象中初始化属性self.name = nameself.age = age# __str__(self)会在当前对象转换为字符串时使用# 它可以用来指定对象转换为字符串的结果def __str__(self):return "Person[name: %s, age %d]"%(self.name,self.age)# 调用类创建对象是,类后面的所有参数都会一次传递给__init__(self)中
p1 = Person("Sakura",10)
print(p1)

  __repr__() 这个特殊方法会在当前对象使用 repr() 函数时调用,它的作用对象在‘交互模式’中直接输出的效果。

object.__repr__(self)
class Person:# __init__(self)会在对象创建后立即执行# __init__(self)可以用来向新创建的对象初始化属性def __init__(self, name, age):# 通过self向新创建堆额对象中初始化属性self.name = nameself.age = age# __repr__(self)这个特殊方法会在当前对象使用repr()函数时调用# 它的作用对象在‘交互模式’中直接输出的效果def __repr__(self):return "Person[name: %s, age %d]"%(self.name,self.age)# 调用类创建对象是,类后面的所有参数都会一次传递给__init__(self)中
p1 = Person("Sakura",10)
print(p1)

  __getattribute__() 方法可以实现属性拦截的作用。

object.__getattribute__(self, name)
class Person:def __init__(self, name, age):self.name = nameself.age = agedef __getattribute__(self, attribute):if attribute == "age":return "直接问别人年龄是不礼貌的哦"else:return object.__getattribute__(self, attribute)p = Person("Sakura", 10)
print(f"name: {p.name}")
print(f"age: {p.age}")

  如果我们想像操作字典的方式用键值对的方式操作对象,可以使用如下方法:

object.__getitem__(self, key)           # 用键值对的方式获取属性
object.__setitem__(self, key, value)    # 用键值对的方式设置属性
object.__delitem__(self, key)           # 用键值对的方式删除属性
class Person:def __getitem__(self, key):print("__getitem()__方法执行了")def __setitem__(self, key, value):print("__setitem()__方法执行了")def __delitem__(self, key):print("__delitem()__方法执行了")p = Person()
p["name"] = "Sakura"
name = p["name"]
del p["name"]

  有关比较的特殊方法。

object.__lt__(self, other)  # 会在对象做小于(<)时调用,该方法的返回值会作为比较结果
object.__le__(self, other)  # 会在对象做小于等于(<=)时调用,该方法的返回值会作为比较结果
object.__eq__(self, other)  # 会在对象做等于(==)时调用,该方法的返回值会作为比较结果
object.__ne__(self, other)  # 会在对象做不等于(!=)时调用,该方法的返回值会作为比较结果
object.__gt__(self, other)  # 会在对象做大于(>)时调用,该方法的返回值会作为比较结果
object.__ge__(self, other)  # 会在对象做大于等于(>=)时调用,该方法的返回值会作为比较结果
class Person:# __init__(self)会在对象创建后立即执行# __init__(self)可以用来向新创建的对象初始化属性def __init__(self, name, age):# 通过self向新创建堆额对象中初始化属性self.name = nameself.age = age# __gt__(self,other)会在对象做小于时调用,该方法的返回值会作为比较结果# 它需要两个参数,self表示当前对象,other表示和当前对象比较的对象def __gt__(self,other):return self.age > other.age# 调用类创建对象是,类后面的所有参数都会一次传递给__init__(self)中
p1 = Person("Sakura",10)
p2 = Person("Mikoto",15)
print(p1 > p2)
print(p2 > p1)

  有关运算的特殊方法:

object.__add__(self, other)
object.__sub__(self, other)
object.__mul__(self, other)
object.__matmul__(self, other)
object.__truediv__(self, other)
object.__floordiv__(self, other)
object.__mod__(self, other)
object.__divmod__(self, other)
object.__pow__(self, other[, modulo])
object.__lshift__(self, other)
object.__rshift__(self, other)
object.__and__(self, other)
object.__xor__(self, other)
object.__or__(self, other)
object.__len__(self)        # 获取对象的长度
object.__bool__(self)       # 将当前对象个转换为布尔值

3.5、对象创建的流程

  p1 = Person() 的运行流程:

  1. 创建一个变量;
  2. 在内存中创建一个空对象;
  3. 自动调用类中 __init__(self) 方法,然后将空对象已经调用类是括号内传入的的参数一同传给 __init__() 方法;
  4. 将对象的 id 赋值给变量;
class Person:# 类代码块中的代码只在类定义的时候执行一次print("我是Person中的代码块")def __init__(self):print("我是",self,"__init__(self)方法")p1 = Person()
p2 = Person()

类代码块中的代码只在类定义的时候执行一次;

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

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

相关文章

深入浅出:Gin框架中的测试与Mock

深入浅出&#xff1a;Gin框架中的测试与Mock 引言 在现代软件开发中&#xff0c;编写高质量的代码离不开有效的测试。对于Web应用程序来说&#xff0c;单元测试、集成测试和端到端测试都是确保系统稳定性和可靠性的重要手段。本文将带你深入了解如何在Gin框架中进行测试&…

未来网络技术的新征程:5G、物联网与边缘计算(10/10)

一、5G 网络&#xff1a;引领未来通信新潮流 &#xff08;一&#xff09;5G 网络的特点 高速率&#xff1a;5G 依托良好技术架构&#xff0c;提供更高的网络速度&#xff0c;峰值要求不低于 20Gb/s&#xff0c;下载速度最高达 10Gbps。相比 4G 网络&#xff0c;5G 的基站速度…

LDR6500U PD取电协议芯片:高效充电与智能管理的典范

在当今快速发展的电子设备市场中&#xff0c;高效、安全、稳定的充电技术已成为衡量设备性能的重要指标之一。而LDR6500U&#xff0c;作为乐得瑞科技有限公司针对USB PD&#xff08;Power Delivery&#xff09;协议及Quick Charge&#xff08;QC&#xff09;协议开发的一款高性…

Plugin - 插件开发05_Solon中的插件实现机制

文章目录 Pre概述插件插件扩展机制&#xff08;Spi&#xff09;插件扩展机制概述插件扩展机制的优势 插件扩展机制实现步骤第一步&#xff1a;定制插件实现类示例代码&#xff1a;插件实现类 第二步&#xff1a;通过插件配置文件声明插件示例插件配置文件&#xff1a;META-INF/…

JAVA-二叉树的概念和性质

目录 一.树形结构 1.1 概念 1.2 树的概念(重要)​编辑 补充&#xff1a;高度和深度的区别 1.3 树的应用 二. 二叉树&#xff08;重点&#xff09; 2.1 概念 2.2 两种特殊的二叉树 2.3 二叉树的性质 2.4 选择题 一.树形结构 1.1 概念 树是一种 非线性 的数据结构&…

SVM的基本思想

一、SVM的基本思想 SVM的基本思想是在样本的向量空间中寻找一个超平面&#xff0c;使得两类样本被分割在平面的两端。这样的平面理论上有无穷多个&#xff0c;但SVM的目标是找到一个最优的超平面&#xff0c;即两侧距离超平面最近的样本点到超平面的距离被最大化的超平面。这个…

【TCP 网络通信(发送端 + 接收端)实例 —— Python】

TCP 网络通信&#xff08;发送端 接收端&#xff09;实例 —— Python 1. 引言2. 创建 TCP 服务器&#xff08;接收端&#xff09;2.1 代码示例&#xff1a;TCP 服务器2.2 代码解释&#xff1a; 3. 创建 TCP 客户端&#xff08;发送端&#xff09;3.1 代码示例&#xff1a;TCP…

day08 接口测试(3)——postman工具使用

下载 postman 的历史版本&#xff1a;Postman 历史版本下载 - 简书 今天开始学习 postman 这个测试工具啦。 【没有所谓的运气&#x1f36c;&#xff0c;只有绝对的努力✊】 目录 1、postman简介 2、postman的安装 3、给postman安装插件——newman 3.1 环境安装 3.1.1 安…

README写作技巧

做一个项目&#xff0c;首先第一眼看上去要美观&#xff0c;这样才有看下去的动力。做项目亦是如此&#xff0c;如果每一步应付做的话&#xff0c;我想动力也不会太大&#xff0c;最终很大概率会放弃或者进度缓慢。 1.README组成 README是对项目的一个说明&#xff0c;它对观看…

渗透测试---burpsuite(5)web网页端抓包与APP渗透测试

声明&#xff1a;学习素材来自b站up【泷羽Sec】&#xff0c;侵删&#xff0c;若阅读过程中有相关方面的不足&#xff0c;还请指正&#xff0c;本文只做相关技术分享,切莫从事违法等相关行为&#xff0c;本人与泷羽sec团队一律不承担一切后果 视频地址&#xff1a;泷羽---bp&…

【Springboot3+vue3】从零到一搭建Springboot3+vue3前后端分离项目之前端环境搭建

【Springboot3vue3】从零到一搭建Springboot3vue3前后端分离项目之前端环境搭建 2 前端环境搭建2.1 环境准备2.2 创建Vue3项目2.3 项目搭建准备2.4 安装Element Plus2.5 安装axios2.5.1 配置&#xff08;创建实例&#xff0c;配置请求&#xff0c;响应拦截器&#xff09;2.5.2 …

11.27-12.5谷粒商城

目录 新增商品 1.上线会员服务 2. 获取分类关联的品牌 3.获取选定分类下的属性分组和属性 4.新增商品vo 5.保存商品信息 6.Spu检索 7.Sku商品检索 新增商品 1.上线会员服务 将会员服务注册到nacos注册中心&#xff0c;启用服务注册发现EnableDiscoveryClient。 同时新增…

深入解析非桥PCI设备的访问和配置方法

往期内容 本文章相关专栏往期内容&#xff0c;PCI/PCIe子系统专栏&#xff1a; 嵌入式系统的内存访问和总线通信机制解析、PCI/PCIe引入 Uart子系统专栏&#xff1a; 专栏地址&#xff1a;Uart子系统 Linux内核早期打印机制与RS485通信技术 – 末片&#xff0c;有专栏内容观看…

ArrayList常见操作源码逐句剖析

目录 前言 正文 1.需要了解的一些字段属性 1.存储 ArrayList 元素的数组缓冲区。 2.集合的大小 3.默认集合容量大小 2.ArrayList对象创建 1.无参构造 2.有参构造1 3.有参构造2 3.添加元素add(E e)以及扩容机制 ​编辑 后言 前言 源码的剖析有助于理解设计模式&…

现代密码学|Rabin密码体制及其数学基础 | 椭圆曲线密码体制及其运算 | DH密钥交换及中间人攻击

文章目录 参考Rabin密码体制及其数学基础中国剩余定理二次剩余Rabin密码体制实例 椭圆曲线密码体制及其运算原理运算规则加密解密实例 DH密钥交换及中间人攻击中间人攻击 参考 现代密码学&#xff5c;Rabin密码体制及其数学基础 现代密码学&#xff5c;椭圆曲线密码体制及其运…

硬件选型规则

光源选型: 先用型号中带H的&#xff0c;没有的选标准的. 光源和光源控制器的搭配需要确保接口一致。 根据型号表中的最佳工作距离和相机的尺寸。 光源控制器选型&#xff1a; 首先选择海康风格系列光源控制器考虑与光源的接口匹配。功率应该满足接近光源功率。检查是否退市…

sharedPreference包的使用总结

文章目录 1 概念介绍2 实现方法3 示例代码我们在上一章回中介绍了"如何自定义评分条"相关的内容,本章回中将介绍如何实现本地存储.闲话休提,让我们一起Talk Flutter吧。 1 概念介绍 Flutter是一套跨平台的UI框架,它不像原生SDK一样提供本地存储功能,因此,我们在…

TCP连接的时候遇到的异常(目标端口没开放)

import asyncioasync def check_port(ip, port, timeout1):"""检查目标 IP 和端口是否开放:param ip: 目标 IP 地址:param port: 目标端口:param timeout: 超时时间&#xff08;秒&#xff09;"""try:reader, writer await asyncio.open_connec…

C总结(C语言知识点,深化重难点)

C语言 1.使用C语言的7个步骤2.ASCII码3.提高程序可读性的机巧4.如何使用多种整形5.打印多种整形6.课移植类型&#xff1a;stdint.h和inttypes.h7.浮点数常量8.浮点值的上溢和下溢9.使用数据类型11.常量和C预处理器12.转换说明的意义12.1转换不匹配13.副作用和序列点14.数组简介…

burpsuite(6)暴力破解与验证码识别绕过

声明!!! 学习视频来自B站UP主泷羽sec&#xff0c;如涉及侵权马上删除文章 视频链接&#xff1a;泷羽sec-bilibili 笔记的只是方便各位师傅学习知识,以下网站只涉及学习内容,其他的都与本人无关,切莫逾越法律红线,否则后果自负 项目地址&#xff1a;https://github.com/f0ng/cap…