python——面向对象——知识汇总一
面向对象技术简介
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 方法:类中定义的函数。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 局部变量:定义在方法中的变量,只作用于当前实例的类。
- 实例变量:在类的声明中,属性是用变量来表示的,这种变量就称为实例变量,实例变量就是一个用 self 修饰的变量。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
例如,有这样一个设计:一个Dog类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例图,Dog是一个Animal)。 - 实例化:创建一个类的实例,类的具体对象。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
面向对象中,常用术语包括:
- 类:可以理解是一个模板,通过它可以创建出无数个具体实例。比如,前面编写的 tortoise 表示的只是乌龟这个物种,通过它可以创建出无数个实例来代表各种不同特征的乌龟(这一过程又称为类的实例化)。
- 对象:类并不能直接使用,通过类创建出的实例(又称对象)才能使用。这有点像汽车图纸和汽车的关系,图纸本身(类)并不能为人们使用,通过图纸创建出的一辆辆车(对象)才能使用。
- 属性:类中的所有变量称为属性。例如,tortoise 这个类中,bodyColor、footNum、weight、hasShell 都是这个类拥有的属性。
- 方法:类中的所有函数通常称为方法。不过,和函数所有不同的是,类方法至少要包含一个 self 参数(后续会做详细介绍)。
例如,tortoise 类中,crawl()、eat()、sleep()、protect() 都是这个类所拥有的方法,类方法无法单独使用,只能和类的对象一起使用。
class tortoise: bodyColor = "绿色" footNum = 4 weight = 10 hasShell = True #会爬 def crawl(self): print("乌龟会爬") #会吃东西 def eat(self): print("乌龟吃东西") #会睡觉 def sleep(self): print("乌龟在睡觉") #会缩到壳里 def protect(self): print("乌龟缩进了壳里") # 实例化类 x = tortoise() # 访问类的属性和方法 print(x.bodyColor) print(x.footNum) print(x.weight) print(x.hasShell) print("===================================") x.crawl() x.eat() x.sleep() x.protect()
============================================================================
定义类
类定义
语法格式如下:
class ClassName: <statement-1> . . . <statement-N>
class 类名: 多个(≥0)类属性... 多个(≥0)类方法...
和变量名一样,类名本质上就是一个标识符,因此我们在给类起名字时,必须让其符合 Python 的语法。
因此,在给类起名字时,最好使用能代表该类功能的单词,例如用“Student”作为学生类的类名;甚至如果必要,可以使用多个单词组合而成,例如初学者定义的第一个类的类名可以是“TheFirstDemo”。
注意,如果由单词构成类名,建议每个单词的首字母大写,其它字母小写。
其实,类属性指的就是包含在类中的变量;而类方法指的是包含类中的函数。
类实例化后,可以使用其属性,实际上,创建一个类之后,可以通过类名访问其属性。
=============================================================================
Python的 __init__() 类构造方法
在创建类时,我们可以手动添加一个 __init__() 方法,该方法是一个特殊的类实例方法,称为构造方法(或构造函数)。
构造方法用于创建对象时使用,每当创建一个类的实例对象时,Python 解释器都会自动调用它。Python 类中,手动添加构造方法的语法格式如下:
def __init__(self,...): 代码块
注意,此方法的方法名中,开头和结尾各有 2 个下划线,且中间不能有空格。Python 中很多这种以双下划线开头、双下划线结尾的方法,都具有特殊的意义
_init__() 方法可以包含多个参数,但必须包含一个名为 self 的参数,且必须作为第一个参数。
也就是说,类的构造方法最少也要有一个 self 参数。
例如,仍以 TheFirstDemo 类为例,添加构造方法的代码如下所示:
class TheFirstDemo: '''这是一个学习Python定义的第一个类''' #构造方法 def __init__(self): print("调用构造方法") # 下面定义了一个类属性 add = 'http://c.biancheng.net' # 下面定义了一个say方法 def say(self, content): print(content)
注意,即便不手动为类添加任何构造方法,Python 也会自动为类添加一个仅包含 self 参数的构造方法。
仅包含 self 参数的 __init__() 构造方法,又称为类的默认构造方法。
显然,在创建 zhangsan 这个对象时,隐式调用了我们手动创建的 __init__() 构造方法。
不仅如此,在 __init__() 构造方法中,除了 self 参数外,还可以自定义一些参数,参数之间使用逗号“,”进行分割。
例如,下面的代码在创建 __init__() 方法时,额外指定了 2 个参数:
注意,由于创建对象时会调用类的构造方法,如果构造函数有多个参数时,需要手动传递参数,
可以看到,虽然构造方法中有 self、name、add 3 个参数,但实际需要传参的仅有 name 和 add,也就是说,self 不需要手动传递参数。
Python类的实例化
我们已经学会如何定义一个类,但要想使用它,必须创建该类的对象。创建类对象的过程,又称为类的实例化。
对已定义好的类进行实例化,其语法格式如下: 类名(参数)
定义类时,如果没有手动添加 __init__() 构造方法,又或者添加的 __init__() 中仅有一个 self 参数,则创建类对象时的参数可以省略不写。
在上面的程序中,由于构造方法除 self 参数外,还包含 2 个参数,且这 2 个参数没有设置默认参数,
因此在实例化类对象时,需要传入相应的 name 值和 add 值(self 参数是特殊参数,不需要手动传值,Python 会自动传给它值)。
Python类对象的使用
定义的类只有进行实例化,也就是使用该类创建对象之后,才能得到利用。总的来说,实例化后的类对象可以执行以下操作:
- 访问或修改类对象具有的实例变量,甚至可以添加新的实例变量或者删除已有的实例变量;
- 调用类对象的方法,包括调用现有的方法,以及给类对象动态添加方法。
类对象访问变量或方法
使用已创建好的类对象访问类中实例变量的语法格式如下:
类对象名.变量名
使用类对象调用类中方法的语法格式如下:
对象名.方法名(参数)
注意,对象名和变量名以及方法名之间用点 "." 连接。
class CLanguage : # 下面定义了2个类变量 name = "C语言中文网" add = "http://c.biancheng.net" def __init__(self,name,add): #下面定义 2 个实例变量 self.name = name self.add = add print(name,"网址为:",add) # 下面定义了一个say实例方法 def say(self, content): print(content) # 将该CLanguage对象赋给clanguage变量 clanguage = CLanguage("C语言中文网","http://c.biancheng.net") #输出name和add实例变量的值 print(clanguage.name,clanguage.add) #修改实例变量的值 clanguage.name="Python教程" clanguage.add="http://c.biancheng.net/python" #调用clanguage的say()方法 clanguage.say("人生苦短,我用Python") #再次输出name和add的值 print(clanguage.name,clanguage.add)
Python self用法详解
在定义类的过程中,无论是显式创建类的构造方法,还是向类中添加实例方法,都要求将 self 参数作为方法的第一个参数。
事实上,Python 只是规定,无论是构造方法还是实例方法,最少要包含一个参数,并没有规定该参数的具体名称。
之所以将其命名为 self,只是程序员之间约定俗成的一种习惯,遵守这个约定,可以使我们编写的代码具有更好的可读性(大家一看到 self,就知道它的作用)。
那么,self 参数的具体作用是什么呢?
打个比方,如果把类比作造房子的图纸,那么类实例化后的对象是真正可以住的房子。
根据一张图纸(类),我们可以设计出成千上万的房子(类对象),每个房子长相都是类似的(都有相同的类变量和类方法),但它们都有各自的主人,那么如何对它们进行区分呢?
当然是通过 self 参数,它就相当于每个房子的门钥匙,可以保证每个房子的主人仅能进入自己的房子(每个类对象只能调用自己的类变量和类方法)。
也就是说,同一个类可以产生多个对象,当某个对象调用类方法时,该对象会把自身的引用作为第一个参数自动传给该方法,
换句话说,Python 会自动绑定类方法的第一个参数指向调用该方法的对象。如此,Python解释器就能知道到底要操作哪个对象的方法了。
总之,无论是类中的构造函数还是普通的类方法,实际调用它们的谁,则第一个参数 self 就代表谁。
===================================================================================
Python类变量和实例变量(类属性和实例属性)
无论是类属性还是类方法,都无法像普通变量或者函数那样,在类的外部直接使用它们。
我们可以将类看做一个独立的空间,则类属性其实就是在类体中定义的变量,类方法是在类体中定义的函数。
在类体中,根据变量定义的位置不同,以及定义的方式不同,类属性又可细分为以下 3 种类型:
1、类体中、所有函数之外:此范围定义的变量,称为类属性或类变量;
2、类体中,所有函数内部:以“self.变量名”的方式定义的变量,称为实例属性或实例变量;
3、类体中,所有函数内部:以“变量名=变量值”的方式定义的变量,称为局部变量。
class CLanguage : # 下面定义了2个类变量 name = "C语言中文网" add = "http://c.biancheng.net" # 下面定义了一个say实例方法 def say(self, content): print(content) #使用类名直接调用 print(CLanguage.name) print(CLanguage.add) print("================================================") #修改类变量的值 CLanguage.name = "Python教程" CLanguage.add = "http://c.biancheng.net/python" print(CLanguage.name) print(CLanguage.add) print("+++++++++++++++++++++++++++++++++++++++++++++++++++++++") print("修改前,各类对象中类变量的值:") clang1 = CLanguage() print(clang1.name) print(clang1.add) clang2 = CLanguage() print(clang2.name) print(clang2.add) print("&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&&") print("修改后,各类对象中类变量的值:") CLanguage.name = "Python教程" CLanguage.add = "http://c.biancheng.net/python" print(clang1.name) print(clang1.add) print(clang2.name) print(clang2.add)
类变量(类属性)
类变量指的是在类中,但在各个类方法外定义的变量。举个例子:
class CLanguage : # 下面定义了2个类变量 name = "C语言中文网" add = "http://c.biancheng.net" # 下面定义了一个say实例方法 def say(self, content): print(content)
上面程序中,name 和 add 就属于类变量。
类变量的特点是,所有类的实例化对象都同时共享类变量,也就是说,类变量在所有实例化对象中是作为公用资源存在的。
类方法的调用方式有 2 种,既可以使用类名直接调用,也可以使用类的实例化对象调用。
通过类名不仅可以调用类变量,也可以修改它的值。
当然,也可以使用类对象来调用所属类中的类变量(此方式不推荐使用)。
注意,因为类变量为所有实例化对象共有,通过类名修改类变量的值,会影响所有的实例化对象。
注意,通过类对象是无法修改类变量的。通过类对象对类变量赋值,其本质将不再是修改类变量的值,而是在给该对象定义新的实例变量
实例变量(实例属性)
实例变量指的是在任意类方法内部,以“self.变量名”的方式定义的变量,其特点是只作用于调用方法的对象。
另外,实例变量只能通过对象名访问,无法通过类名访问。
通过类对象可以访问类变量,但无法修改类变量的值。
这是因为,通过类对象修改类变量的值,不是在给“类变量赋值”,而是定义新的实例变量。
类中,实例变量和类变量可以同名,但这种情况下使用类对象将无法调用类变量,它会首选实例变量,这也是不推荐“类变量使用对象名调用”的原因。
注意:和类变量不同,通过某个对象修改实例变量的值,不会影响类的其它实例化对象,更不会影响同名的类变量。
============================================================================================
Python实例方法、静态方法和类方法
和类属性一样,类方法也可以进行更细致的划分,具体可分为类方法、实例方法和静态方法。
和类属性的分类不同,区分这 3 种类方法是非常简单的,即采用
@classmethod 修饰的方法为类方法;
@staticmethod 修饰的方法为静态方法;
不用任何修改的方法为实例方法。
Python类实例方法
通常情况下,在类中定义的方法默认都是实例方法。类的构造方法理论上也属于实例方法,只不过它比较特殊。
实例方法最大的特点就是,它最少也要包含一个 self 参数,用于绑定调用此方法的实例对象(Python 会自动完成绑定)。
实例方法通常会用类对象直接调用。
Python类方法
Python 类方法和实例方法相似,它最少也要包含一个参数,只不过类方法中通常将其命名为 cls,Python 会自动将类本身绑定给 cls 参数(注意,绑定的不是类对象)。
也就是说,我们在调用类方法时,无需显式为 cls 参数传参。
和 self 一样,cls 参数的命名也不是规定的(可以随意命名),只是 Python 程序员约定俗称的习惯而已。
和实例方法最大的不同在于,类方法需要使用@classmethod
修饰符进行修饰。
注意,如果没有 @classmethod,则 Python 解释器会将 fly() 方法认定为实例方法,而不是类方法。
类方法推荐使用类名直接调用,当然也可以使用实例对象来调用(不推荐)。
Python类静态方法
静态方法,其实就是我们学过的函数,和函数唯一的区别是,静态方法定义在类这个空间(类命名空间)中,而函数则定义在程序所在的空间(全局命名空间)中。
静态方法没有类似 self、cls 这样的特殊参数,因此 Python 解释器不会对它包含的参数做任何类或对象的绑定。也正因为如此,类的静态方法中无法调用任何类属性和类方法。
静态方法需要使用@staticmethod
修饰
静态方法的调用,既可以使用类名,也可以使用类对象。
===============================================================================
Python类调用实例方法
实例方法的调用方式其实有 2 种,既可以采用
1、类对象调用;
2、类名调用。
如果想通过类名直接调用实例方法,就必须手动为 self 参数传值。
PS:通过手动将 clang 这个类对象传给了 self 参数,使得程序得以正确执行。实际上,这里调用实例方法的形式完全是等价于 clang.info()
总的来说,Python 中允许使用类名直接调用实例方法,但必须手动为该方法的第一个 self 参数传递参数,这种调用方法的方式被称为“非绑定方法”。
========================================================================================
Python描述符详解
PS:就是类的封装,类似于java中的getter、setter方法,这样就明白了。
本质上看,描述符就是一个类,只不过它定义了另一个类中属性的访问方式。换句话说,一个类可以将属性管理全权委托给描述符类。
描述符是 Python 中复杂属性访问的基础,它在内部被用于实现 property、方法、类方法、静态方法和 super 类型。
描述符类基于以下 3 个特殊方法,换句话说,这 3 个方法组成了描述符协议:
- __set__(self, obj, type=None):在设置属性时将调用这一方法(本节后续用 setter 表示);
- __get__(self, obj, value):在读取属性时将调用这一方法(本节后续用 getter 表示);
- __delete__(self, obj):对属性调用 del 时将调用这一方法。
其中,实现了 setter 和 getter 方法的描述符类被称为数据描述符;反之,如果只实现了 getter 方法,则称为非数据描述符。
实际上,在每次查找属性时,描述符协议中的方法都由类对象的特殊方法 __getattribute__() 调用(注意不要和 __getattr__() 弄混)。
也就是说,每次使用类对象.属性(或者 getattr(类对象,属性值))的调用方式时,都会隐式地调用 __getattribute__(),它会按照下列顺序查找该属性:
- 验证该属性是否为类实例对象的数据描述符;
- 如果不是,就查看该属性是否能在类实例对象的 __dict__ 中找到;
- 最后,查看该属性是否为类实例对象的非数据描述符。
下面这个调用了 其getter方法:
下面这个调用了setter方法赋值:
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
2023-02-25 java——spring boot集成RabbitMQ——如何实现手动ack
2023-02-25 java——spring boot集成RabbitMQ——spring boot实现路由模式——生产者
2023-02-25 java——spring boot集成RabbitMQ——spring boot实现路由模式——消费者
2023-02-25 java——spring boot集成RabbitMQ——spring boot实现发布订阅模式——生产者
2023-02-25 java——spring boot集成RabbitMQ——spring boot实现发布订阅模式——消费者
2023-02-25 java——spring boot集成RabbitMQ——windows本地安装和运行
2023-02-25 java——spring boot集成RabbitMQ——topics模式——实现消费者