目录
一、类和对象
1.类的定义
类是创建对象的基础模板。它为对象提供了创建的要求。类由以下三部分组成:
(1)类名: 类的名称,它的首字母必须是大写,如:Cat
(2)属性: 定义属性(变量)用于描述事物的特征,比如:人的姓名、年龄等特征是类中定义的数据。
(3)方法: 方法(函数)用于描述事物的行为,比如,人会说话、微笑等类的行为。
示例:
上述例子中,我们定义了一个Cat的类,类的对象的参数固定第一个self,self代表类的对象自己,后面可引用对象的属性和方法,self 可以有'类属性'和'实例属性'。
所谓类属性,即:由类的所有实例共享。它们在类定义的顶部声明,不需要使用 self 参数。
所谓实例属性,即:属于类的每个特定实例,每个实例都有独自的属性内容。它们在类的初始化方法 init 中 通过使用 self 参数来声明。
例子中的move、jump、index都是实例属性。
类属性示范:
python
class Cat:
black = "black cat detective" # 这里black是类属性
2.根据对象创建类
格式如下:
对象名 = 类名(自定义参数)
python
# 创建一个对象,并对该变量对象保持引用
tom = Cat(2,1)
紧接着给对象加属性的格式:
对象名 . 新的属性值 = 值
python
# 添加 颜色 属性
tom.color = '橘色'
完整栗子:
python
class Cat: # 定义一个Cat父类
def __init__(self, move, scratch):
self.move = move # 给Cat类增加move属性的构造方法
self.scratch = scratch # 将参数scratch赋值给scratch属性
# 实例属性 index
self.index = {'weight': f'{0.5}kg', 'height': f'{5} cm'}
# 创建一个对象,并对该变量对象保持引用
tom = Cat(2, 1)
# 给创建好的对象增加额外的属性
tom.color = '橘色'
# 访问属性
print("一只" + tom.color + "的猫干的好事!")
print("打碎杯子:", tom.move)
print("抓坏枕头:", tom.scratch)
print(tom.index)
二、构造和析构
1.构造方法
如果每创建一个类的对象,建一个对象,还想就添加一次属性,这样显然非常麻烦。
为此Python 提供了一个构造方法来解决这个问题,可以在创建对象的时候就设置多个属性。该方法就是上面用到的 init (两个下划线开头、两个下划线结尾),当创建类的实例属性时,系统会自动调用构造方法,从而实现对类进行初始化的操作。
(1)不带参数的构造方法
即:就单独一个(self)。示范:
python
class Car:
# 不带参数的构造方法
def __init__(self):
self.color = '黑色'
def wait(self):
print(f"一辆{self.color}的车在等候...")
car = Car()
car.wait()
(2)带参数的构造方法
有时属性值一样,不利于构造的扩展。所以通过传入参数来修改属性的值就很方便。
示范:
python
class Car:
# 带参数构造方法
def __init__(self, color):
self.color = color
# 鸣笛
def toot(self):
print(f"{self.color}色的车在鸣笛...")
# 等候
def wait(self):
print(f"{self.color}色的车在等候...")
# 对象1
BMW = Car("白")
# 对象2
TOYOTA = Car("灰")
# 开始调用
BMW.toot()
TOYOTA.wait()
2.析构方法
当一个对象的运行周期结束时,Python 解释器会通过调用__del__()的方法删除调用的对象,来释放内存资源,这样的方法称为'析构'。
继续上面的例子(带有析构):
python
class Car:
# 带参数构造方法
def __init__(self, color):
self.color = color
# 鸣笛
def toot(self):
print(f"{self.color}色的车在鸣笛...")
# 等候
def wait(self):
print(f"{self.color}色的车在等候...")
'''根据python自动回收垃圾机制会自动
删除周期结束的对象并释放内存空间'''
def __del__(self):
print("-------")
# 对象1
BMW = Car("白")
# 对象2
TOYOTA = Car("灰")
# 开始调用
BMW.toot()
TOYOTA.wait()
del BMW # 手动删除调用的对象1,释放内存空间
print("BMW对象已被删除")
del TOYOTA # 手动删除调用的对象2,释放内存空间
print("TOYOTA对象已被删除")
总之,处理多个对象或者有循环调用对象时,析构是个方法。并且Python会在对象生命周期结束时自动进行垃圾回收,所以有时我们可以不需要显式的定义__del__方法。
三、重载
重载通常指的是能够定义多个同名函数,但是它们的参数列表(类型或数量)不同。Python本身不支持函数重载的语法,因为它是动态类型的语言,参数的类型在运行时确定。不过,可以通过默认参数值、可变参数(不定长参数)或使用装饰器等方式来模拟类似重载的行为。
与"重载"相比,重写发生在继承体系中,子类中的方法与父类中同名方法具有相同的参数列表和返回类型。子类通过重写方法来提供特定的实现,覆盖父类的行为。
1.定制对象的字符串形式
(1)__str__实例方法
使用__str__方法,即:能让print打印出调用的参数结果,例:
python
class Vehicle:
def __init__(self, price, fuel_consumption):
# 给初始化的参数赋值给实例的属性
self.price = price
self.fuel_consumption = fuel_consumption
# 重载方法
def __str__(self): # 将对象转换为字符串时能被自动调用
return f"售价:{self.price} 油耗:{self.fuel_consumption}"
su7 = Vehicle("22万", 0) # 创建一个Vehicle的实例,传递22万、0 参数
print(su7)
// ^-^
如果没有写__str__实例方法:
就只会显示对象所在的地址(这并不是我们所想要的结果)
(2)__repr__实例方法
重载 repr 方法,可以保证各种操作下都能正确获得实例对象自定义的字符串形式。与__str__方法相比, repr 用于获取对象的字符串表示时,通常用于开发者调试。当使用__repr__ ()函数或在交互式解释器中打印对象时,__repr__方法被调用。__repr__应该返回一个字符串,且该字符串应该是一个有效的Python表达式,能够重新创建该对象。
示例:
(3)__str__和__repr__实例方法
总之,str__和__repr 都能对自定义对象返回有效的字符串形式。
2.运算符重载
Python 中的运算符重载是一种特殊的多态性形式,运算符重载让我们能够对自定义的对象使用熟悉的运算符,如加法(+)、减法(-)、乘法(*)等。
就比如以下代码,我们给加号赋予一个作用:
python
class Shop:
def __init__(self, price, bonus_point):
self.price = price
self.bonus_point = bonus_point
# 通过两个对象的相加,返回到类中
def __add__(self, other):
return Shop(self.price + other.price,
self.bonus_point + other.bonus_point)
def __str__(self): # 确保能返回我们自定义的字符串
return f"消费金额:{self.price},奖励积分:{self.bonus_point}"
def __repr__(self): # 保证各种操作下都能让自定义对象有字符串形式
return f"消费金额:{self.price},奖励积分:{self.bonus_point}"
nanfu_battery = Shop(9, 0.5)
air_conditioning = Shop(6999, 100)
# 这里就是通过自定义对象的相加给'+'运算符 赋予的功能
total = nanfu_battery + air_conditioning
print(total)
在 Python 中,运算符重载通过在类中定义特殊方法来实现。这些特殊方法以双下划线开始和结束,例如__add__、sub、__mul__等,常见的如下:
(1)加法运算重载
当两个实例对象进行加法时,自动调用__add__方法,例:
python
class Vector: # 定义一个 Vector(向量)的类
# 构建函数,通过[:]切片复制一个新对象,而不影响原来的对象
def __init__(self, other):
self.data = other[:]
# 加法重载
def __add__(self, other):
# 计算 self.data 和 other.data 的长度的最小值
min_len = min(len(self.data), len(other.data))
# 创建一个变量,用于存放结果
result_list = []
# 遍历两个列表的最小长度
for i in range(min_len):
result_list.append(self.data[i] + other.data[i])
# 判断哪个列表更长,并添加剩余的元素
if len(self.data) > min_len:
result_list.extend(self.data[min_len])
elif len(other.data) > min_len:
result_list.extend(other.data[min_len])
# 返回包含相加的结果
return Vector(result_list)
# 创建Vector(向量)类的两个实例
one = Vector([4, 5])
two = Vector([6, 7])
demo_sum = one + two
print("相加结果:", demo_sum.data)
其实、在单纯的调用运算符重载的计算中,主要是要考虑好计算的边界问题就行吧.......(好难啊!)
(2)索引和分段重载
索引和分片相关的重载方法主要包括以下三个:
示例:
python
class MyList:
# 先构造一个初始化函数
def __init__(self, initial_data):
self.data = initial_data
# 定义索引、分片的重载
def __getitem__(self, key):
return self.data[key]
# 定义索引、分片赋值的重载
def __setitem__(self, key, value):
self.data[key] = value
# 删除索引、分片的重载
def __delitem__(self, key):
del self.data[key]
# 使用repr函数用来返回self.data字符串形式
def __repr__(self):
return repr(self.data)
# 创建一个实例
list = MyList([1, 2, 3, 4, 5])
print(list[1]) # 索引出位置1的值
print(list[:]) # 分片返回列表全部的值
print(list[1:3]) # 分片位置1-3(不含)的值
print("-"*20) # 一条分割线...
list[1] = 10 # 将索引1的元素改为10
list[2:4] = [8, 9] # 将索引2到3的元素替换为[8, 9]
print(list) # 输出新的列表
print("-"*20) # 一条分割线...
del list[1] # 删除索引1的元素
del list[1:3] # 删除索引1到2的元素
print(list) # 再输出新的列表
P.S.
端午假期愉快!\(*^▽^*)/