Python类的常用魔法方法

Posted 礁之

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python类的常用魔法方法相关的知识,希望对你有一定的参考价值。

文章目录

一. __init__()

# 在Python类中,有一类方法,这类方法以 两个下划线开头和结尾,并且在满足某个特定条件的情况下会自动调用,这类方法称为魔法方法
"""
__init__()
调用时机: 在创建对象之后,会立即调用
作用:
    1. 用来给对象添加属性,给对象添加一个初始值(构造函数)
    2. 代码的业务需求,每创建一个对象,都需要执行的代码可以写在__init__中
"""


class Dog(object):
    def __init__(self, name):
        print('我是__init__方法,我被调用了')
        # 对象.属性名 = 属性值 ,直接在类中代码定义属性,之后创建对象时,如果不修改属性值,那么所有对象的属性值都是一样的
        # self.name = '小狗'
        self.name = name


# 创建对象,每次创建都会执行__init__方法的代码
# Dog()  # 这里对象已经创建,只不过没有使用变量保存,后续代码无法使用

dog = Dog('大黄')
print(dog.name)

dog1 = Dog('小白')
print(dog1.name)

# 注意点: 如果__init__方法中,有除了self之外的形参,那么在创建对象时,需要给额外的形参传递实参值,否则会报错  类名(实参值)

二. __str__()

"""
__str__()
调用时机:
    1. print(对象),会自动调用__str__方法,打印输出的结果是__str__方法的返回值
    2. str(对象) 类型转换,将自定义对象转换为字符串的时候,会自动调用
应用:
    1. 打印对象的时候,输出一些属性信息
    2. 需要将对象转换为字符串类型的时候
注意点:
    方法必须返回一个字符串,此方法通常只有 self 一个参数
"""


class Dog(object):
    def __init__(self, name, age):
        # 添加属性
        self.name = name
        self.age = age

    def __str__(self):
        print('我是__str__,我被调用了')  # 实际代码不写这种的,只用写return即可
        # 必须返回一个字符串,否则会报错
        return f"小狗的名字是self.name,年龄是self.age"


# 创建对象
dog = Dog('大黄', 2)
print(dog)  # 没有定义 __str__ 方法时,print(对象)时,默认输出对象的引用地址

str_dog = str(dog)  # 没有定义 __str__ 方法时,进行类型转换,赋值的也是引用地址
print(str_dog)

三. __del__()

"""
__del__()
析构函数
调用时机:
    对象在内存中被销毁删除的时候会自动调用__del__方法
    1. 程序代码运行结束,在程序运行过程中,创建的所有对象和变量都会被删除销毁
    2. 使用  del变量  删除变量,将这个对象的引用计数变为0,然后就会自动调用__del__方法
应用场景:
    对象被删除销毁的时候,要书写的代码可以写在__del__方法中,一般很少使用

引用计数: 是Python内存管理的一种机制,是指一块内存,有多少个变量在引用,有一个变量引用计数就是1,三个变量就是3
    1. 当一个变量,引用一块内存的时候,引用计数加1
    2. 当删除一个变量或者这个变量不再引用这块内存时,引用计数减1
    3. 当内存的引用计数变为0时,这块内存被删除,内存中的数据会被销毁
    例如:
    my_list = [1, 2]   # 1
    my_list1 = my_list   # 2
    del my_list   # 1
    def my_list1   # 2
"""


class Dog(object):
    def __init__(self, name, age):
        # 添加属性
        self.name = name
        self.age = age

    def __str__(self):
        return f"小狗的名字是self.name,年龄是self.age"

    def __del__(self):
        print(f"我是__del__方法,我被调用了,self.name销毁了.....")


# 创建一个对象,每有一个对象就会调用一次,程序结束,会调用__del__方法
#dog = Dog('小黄',2)
#dog1 = Dog('小白',3)

# 引用计数为0会立即调用
dog = Dog('小花',4)   # 此时dog变量引用了对象,引用计数为1
dog2 = dog  # 此时dog2变量和dog变量都指向了对象,引用计数为2
print('第一次删除之前')
del dog # dog 变量不能使用,小花引用计数变为1
print('第一次删除之后')
print('第二次删除之前')
del dog2 # dog2 变量不能使用,小花引用计数变为0,会立即调用__del__方法
print('第二次删除之后')

四. __repr__()

"""
__repr__()
调用时机:
    将对象存入列表(容器)中,直接打印列表
注意点:
    1. 方法必须返回一个字符串,此方法通常只有 self 一个参数
    2. 和__str__不同的就是,__str__是在打印对象时输出,而__repr__是把对象放在列表(容器)中,然后打印列表输出的
"""

my_list = ['hello', 'python', 'cpp']  # 列表中存储了三个字符串对象

# 因为字符串也是对象,但是使用print时,并没有打印内存地址
print(my_list)


class Dog(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        return f'self.name,self.age'

    def __repr__(self):
        """
        repr方法和str方法非常类似, 也是必须返回一个字符串
        """
        return f'self.name'


my_list1 = [Dog("大黄", 2), Dog("小白", 4), Dog("小花", 6)]
# 但是自己定义后,打印列表,输出的是引用地址,这个时候,使用__repr__,在直接打印列表的时候,就会输出__repr__方法返回的字符串
print(my_list1)

dog = Dog("大黄", 2)
print(dog)

五. 使用案例

  • 烤地瓜
# -*- coding: utf-8 -*-
# Niko create
"""
烤地瓜规则:
1. 地瓜有自己的状态,默认是生的,地瓜可以进行烧烤
2. 地瓜有自己烧烤的总时间,由每次烧烤的时间累加得出
3. 地瓜烧烤时,需要提供本次烧烤的时间
4. 地瓜烧烤时,地瓜状态随着烧烤总时间的变化而变化,0-3生的,3-6半生不熟.6-8熟了,>=8烤糊了
5. 输出地瓜信息时,可以显示地瓜的状态和烧烤的总时间


封装的小套路:
1. 根据文字的描述信息,确定对象,对象有什么,就是属性
2. 根据文字的描述信息,对象能干什么,就是方法
3. 根据文字的描述信息,确定方法怎么书写
"""


class Potato(object):
    def __init__(self):
        self.status = '生的'
        self.total_time = 0
        self.name_list = [] # 保存调料的列表

    def cook(self, time):
        # 计算总时间
        self.total_time += time
        # 修改地瓜的状态
        if self.total_time < 3:
            self.status = '生的'
        elif self.total_time < 6:
            self.status = '半生不熟'
        elif self.total_time < 8:
            self.status = '熟了'
        else:
            self.status = '烤糊了'

    def __str__(self):
        # 字符串,join(列表),将字符串添加到列表中的每个元素之间,组成新的字符串
        buf_list = ','.join(self.name_list)
        if self.name_list:
            return f'地瓜的状态为self.status>>>>烧烤总时间为self.total_time>>>>调料有buf_list'
        else:
            return f'地瓜的状态为self.status>>>>烧烤总时间为self.total_time>>>>没有添加调料'

    def add(self, name):
        self.name_list.append(name)


potato = Potato()
print(potato)
potato.add('油')
potato.cook(4)
potato.add('辣椒面')
print(potato)
potato.cook(3)
potato.add('孜然粉')
print(potato)
  • 搬家具
# -*- coding: utf-8 -*-
# Niko create
"""
搬家具规则:
1. 家具分不同的类型,并且占用不同的面积
2. 输出家具信息时,显示家具的类型和家具的占用面积
_____________________
3. 房子有自己的地址和占用面积
4. 房子可以添加家具,如果房子的剩余面积可以容纳家具,则提示家具添加成,否则提示失败
5. 输出房子信息时,可以显示房子的地址,占用面积,剩余面积
"""


# 定义家具类
class Furniture(object):
    def __init__(self, name, area):
        # 类型
        self.name = name
        # 面积
        self.area = area

    def __str__(self):
        return f'家具类型self.name>>>>占用面积self.area'


class House(object):
    def __init__(self, address, area):
        self.address = address
        self.h_area = area
        self.furniture_list = []
        self.free_area = area  # 房子的剩余面积

    def add_furniture(self, obj_furniture):
        """
        此方法用来添加家具
        obj_furniture 需要是一个对象
        """
        if self.free_area >= obj_furniture.area:
            self.furniture_list.append(obj_furniture.name)
            # 修改剩余面积
            self.free_area -= obj_furniture.area
            print(f'家具obj_furniture.name添加成功')
        else:
            print('添加失败,面积不够')


    def __str__(self):
        # 自定义家具类,将该类的对象添加到列表(容器)中,直接打印列表,显示的是 自定义对象的引用地址
        # furniture_list = [obj.name for obj in obj_furniture]
        # 上面直接在列表添加时,使用obj_furniture.name,就无需上面的列表推导式
        furniture_list = ",".join(self.furniture_list)
        if furniture_list:
            return f'房子的地址是self.address>>>>占用面积self.h_area>>>>剩余面积self.free_area>>>>家具有furniture_list'
        else:
            return f'房子的地址是self.address>>>>占用面积self.h_area>>>>剩余面积self.free_area>>>>没有家具'


# 创建家具对象
bad = Furniture('沙发',15)
computer = Furniture('i9-14750F-GTX4090',5)
table = Furniture('桌子',2)

# 创建房子对象
zhang_house = House('海淀',20)

# 添加家具,输出已经添加好的家具和剩余面积
zhang_house.add_furniture(bad)
zhang_house.add_furniture(computer)
zhang_house.add_furniture(table)
print(zhang_house.free_area)
print(zhang_house.furniture_list)

# 输出家具和房子的信息
print(bad)
print(computer)
print(table)
print(zhang_house)

以上是关于Python类的常用魔法方法的主要内容,如果未能解决你的问题,请参考以下文章

Python类的常用魔法方法

Python类的常用魔法方法

python面向对象方式-烤地瓜

python进阶之类常用魔法方法和魔法属性

Python 常用魔法方法(下)

4.python中常用的魔法方法(长期更新)