Python 魔术方法(Magic Methods)的触发时机



魔术方法的简介

所谓魔法方法,它的官方的名字实际上叫special method

是Python的一种高级语法,允许你在类中自定义函数,并绑定到类的特殊方法中。

无论是magic methods还是魔术方法,在官方文档中是没有出现过的,但这些名称都被广泛的使用着。

special method的特点,就是method的名字前后都有两个下划线,所以这些方法也被称为dunder methods

在我们平时写程序的时候,已经或多或少的接触过不少的魔术方法,比如:__init____str__就很常见。

这些方法在Python中扮演着重要的角色,允许开发者对Python内置的操作进行自定义,从而使对象的行为更加符合特定的需求。

魔术方法的作用

  • 定制对象的行为: 通过重写魔术方法,可以改变对象对特定操作的响应,例如加法、减法、字符串表示、类型转换等。
  • 实现操作符重载: 允许改变对象在使用内置操作符时的行为,比如+-*等。
  • 提供内置函数的支持: 例如len()iter()等内置函数,在调用时会尝试查找对象对应的魔术方法。
  • 实现上下文管理:__enter____exit__方法用于实现with语句的上下文管理。
  • 简化对象的使用: 通过提供对常见任务(如迭代或比较)的内置支持,可以简化对象的使用。

魔术方法汇总

在这里插入图片描述

特殊属性

属性含义
__name__类、函数、方法的名字
__module__类定义所在的模块名
__class__对象或类所属的类
__bases__类的基类的元组
__doc__类、函数的文档字符串,如果没有定义则为None
__mro__类的mro,class.mro()返回的结果保存在此
__dict__类或者实例的属性,可写的字典
__dir__返回类或者对象的所有成员名称列表,dir()函数就是调用__dir__();如果提供__dir__()则返回属性的列表,否则会尽量从__dict__属性中收集信息

__init__初始化

  • 作用说明: 构造函数,用于初始化新创建的对象,当创建对象时自动调用此方法
  • 应用场景: 文件的打开、数据的获取、函数执行前的准备
  • 触发时机: 使用类名创建对象时
class Cola():
    # 初始化方法
    def __init__(self):
        self.brand = 'Coca-Cola'

    # 成员方法
    def drink(self): 
        print('Pepsi-Cola')

# 实例化类就会自动触发执行__init__方法
cola = Cola()
print(cola.brand)



# 构造函数
class Cola():
    # 初始化方法
    def __init__(self,brand,price):
        self.brand = brand
        self.price = price

    # 成员方法
    def drink(self):
        print('Pepsi-Cola')

# 实例化类就会自动触发执行__init__方法
coke = CocaCola('Coca-Cola',4)
print(coke.brand)
print(coke.price)

__new__ 构造方法

  • 作用说明: 对象初始化时执行__new__,目的是为该对象分配内存空间
  • 应用场景: 设计模式中的单例模式
  • 触发时机: 实例化对象时自动触发执行(在 __init__ 之前执行)
  • 方法参数: 1.cls接收当前类,2.其他参数根据初始化方法的参数进行决定
  • 方法返回: 必须返回object.__new__(cls)进行对象的创建,没有返回值则实例化对象的结果为None
  • 注意事项: __new__ 方法的参数和__init__方法的参数要保持一致,除了第一个参数
# 定义一个人类
class Person():
    # 构造方法
    def __new__(cls, *args, **kwargs):
        print('触发了构造方法...')
        print(args)
        print(kwargs)
        # 如果在该方法中没有返回对象,则对象无法创建
        print(cls)  # 将当前类传递进去
        return object.__new__(cls)

    # 初始化方法
    def __init__(self,name,age,sex):
        print('触发了初始化方法...')
        self.name = name
        self.age = age
        self.sex = sex

    # 析构方法
    def __del__(self):
        print('触发了析构方法...')
        pass

# 实例化对象
zsf = Person('张三丰',180,'男')
print('张三丰:',zsf)	# 对象创建成功

__str__ 对象描述

  • 作用说明:返回一个对象的非正式或可打印的字符串表示,可以自定义输出信息
  • **应用场景:**当尝试将一个对象转换为字符串时
  • **触发时机:**当使用print函数或str()函数时触发
class Person:
    
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        # 返回一个简洁的、易于阅读的字符串
        return f"Person(name={self.name}, age={self.age})"
    
    
# 创建一个Person对象
p = Person("Alice", 30)

# 使用str函数或print函数时,会调用__str__方法
print(p)          # 输出: Person(name=Alice, age=30)
print(str(p))     # 输出: Person(name=Alice, age=30)

__repr__ 对象描述

  • 作用说明: 返回一个对象的官方或无歧义的字符串表示
  • 应用场景: 当尝试将一个对象转换为字符串时
  • 触发时机: 在使用repr方法对当前对象进行转换时自动触发
  • 注意事项: 正常情况下,如果没有__str__方法,该方法就会代替,也就是优先级低于__str__
class Person:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def __str__(self):
        # 返回一个简洁的、易于阅读的字符串
        return f"Person(name={self.name}, age={self.age})"

    def __repr__(self):
        # 返回一个精确的、官方的字符串表示
        return f"Person('{self.name}', {self.age})"
    
    
# 创建一个Person对象
p = Person("Alice", 30)

# 使用str函数或print函数时,会调用__str__方法
print(p)          # 输出: Person(name=Alice, age=30)
print(str(p))     # 输出: Person(name=Alice, age=30)

# 使用repr函数时,会调用__repr__方法
print(repr(p))    # 输出: Person('Alice', 30)

__call__ 模糊对象和函数

  • 作用说明: 允许对象像函数那样被调用
  • 应用场景: 当尝试将一个对象当作函数调用
  • 触发时机: 把对象当作函数直接调用时自动触发执行
# 定义一个人类
class Person():
    # 构造方法
    def __new__(cls, *args, **kwargs):
        print('触发了构造方法...')
        print(args)
        print(kwargs)
        # 如果在该方法中没有返回对象,则对象无法创建
        print(cls)  # 将当前类传递进去
        return object.__new__(cls)

    # 初始化方法
    def __init__(self,name,age,sex):
        print('触发了初始化方法...')
        self.name = name
        self.age = age
        self.sex = sex

    def __call__(self, *args, **kwargs):
        print('你把对象当成了函数使用...')

# 实例化对象
zsf = Person('张三丰',180,'男')
print('张三丰:',zsf)	# 对象创建成功

zsf()   # 如果没有__call__方法无法直接调用对象

__del__析构方法

  • 作用说明: 析构函数,用于清理资源
  • 应用场景: 如在初始化方法中打开的文件、连接的资源,可以在析构中关闭
  • 触发时机: 当前类实例化的对象被销毁时,自动触发执行
  • 注意事项: 是对象被销毁时触发了这个方法,而不是这个方法销毁了对象

回收机制:

  1. 当程序执行完毕,内存中所有的资源都会被销毁释放
  2. 使用del关键字手动删除
  3. 对象没有被任何对象被引用时,会自动销毁
import time


class writeLog():
    fileUrl = './'  # 日志文件的路径
    fileName = time.strftime('%Y-%m-%d') + '.log'  # 日志文件的名称

    # 初始化方法
    def __init__(self):
        # 打开文件
        self.fileObj = open(self.fileUrl + self.fileName, 'a+', encoding='utf-8')

    # 写日志的方法
    def log(self, s):
        print(f'假设把日志:{s}写入文件中')

    # 析构方法
    def __del__(self):
        print('析构方法触发执行,关闭打开的文件')
        # 在对象被销毁时,关闭初始化方法中打开的文件对象
        self.fileObj.close()


log = writeLog()
log.log('今天天气很不好!')
del log  # 如果此时销毁log对象,则先行触发析构方法,不会将日志写入文件
print('---注意销毁顺序')  # 销毁顺序遵从回收机制

__len__ 长度计算

  • 作用说明: 定义了当使用len()函数获取对象长度时的行为。它应该返回一个整数,表示对象中的元素个数
  • 应用场景: 当想要自定义的类能够支持len()函数,即能够获取对象中的元素个数时,需要实现__len__方法
  • 触发时机: 当使用len()函数获取对象的长度时,__len__方法会被触发
class CustomContainer:
    def __init__(self):
        self.items = []

    def add(self, item):
        self.items.append(item)

    def __len__(self):
        return len(self.items)

# 使用 CustomContainer 类
container = CustomContainer()
container.add("apple")
container.add("banana")
container.add("cherry")

length = len(container)  # 触发 __len__ 方法
print(length)  # 输出:3

__boor__ 布尔转换

  • 作用说明: 定义了当对象被用在需要布尔值的上下文中时的行为。它应该返回一个布尔值TrueFalse,表示对象的真值状态
  • 应用场景: 当想要自定义的类能够支持布尔上下文,比如if语句while循环的条件判断时,需要实现__bool__方法。
  • 触发时机: 当对象被用在一个需要布尔值的上下文中时,比如在if语句的条件判断或作为循环的条件时,__bool__方法会被触发;如果类中没有定义__bool__方法,Python 会尝试调用__len__方法,如果对象是可迭代的,并且长度为0,则返回False,否则返回True
class Demo():
    listUrl = [1,3,5,7,9]

    # 可以代替对象使用len函数,并返回一个指定的整型
    def __len__(self):
        return len(self.listUrl)

    # 可以代替对象进行str或者print的字符串信息返回便于用户读取
    def __str__(self):
        return '<当前类实例对象的描述 str...>'

    # 同样可以代替对象进行描述,但存在的目的在于开发者调试
    def __repr__(self):
        return '<当前类实例对象的描述 repr...>'

    # 可以代替对象使用bool函数,并返回一个布尔类型
    def __bool__(self):
        return bool(self.listUrl)
---------------------------------------------------------------

# 实例化对象
obj = Demo()

# len
print(len(obj))
# str 如果没有该方法,则打印的是对象的内存地址
print(obj)
# repr 如果和str方法一起实现,则需要使用对象调用repr函数
print(obj.__repr__())
# bool 
print(bool(obj))
---------------------------------------------------------------

# str 和 repr 函数都可以把其他类型的值转为字符串
num = 521
print(str(num),type(str(num)))      # 521 <class 'str'>
print(repr(num),type(repr(num)))    # 521 <class 'str'>

# repr解析str类型的值时带了引号
s = '521'
print(str(s),type(str(s)))      # 521 <class 'str'>
print(repr(s),type(repr(s)))    # '521' <class 'str'>

'''
str 和 repr 函数都能够把其他类型的数据转为字符串类型
str 函数会把对象转为更适合阅读的形式返回
repr函数会把对象转为解释器更容易读取的形式返回
如果数据对象并没有更明显的区别,str和repr的结果是一样的
'''

__enter__ 进入

  • 作用说明: __enter__方法定义了当使用with语句时,会话管理器在块被初始创建时要产生的行为。它的返回值通常绑定到with语句的目标或as后面的变量上,以便在代码块中使用
  • 应用场景: __enter__方法通常与with语句一起使用,用于定义上下文管理器的行为。它可以用于管理资源,如文件、网络连接、数据库连接等,确保在代码块执行完毕后资源能够被正确释放
  • 触发时机:with语句被执行时,首先会调用__enter__方法。在__enter__方法执行完毕后,代码块中的语句开始执行。无论代码块是否发生异常,当代码块执行完毕后,都会调用__exit__方法

__exit__ 退出

  • 作用说明: 清理和释放在__enter__方法中获取的资源
  • 应用场景: 最常见的应用场景是资源管理,如文件、网络连接、数据库连接、锁等。__exit__ 方法确保这些资源在代码块执行完毕后能够被正确释放或关闭,防止资源泄露。
  • 触发时机:with语句块正常执行完毕或发送异常(无论异常有没有被捕捉)时

上下文管理器

class MyFileContext:
    def __enter__(self, filename):
        self.file = open(filename, 'r')
        return self.file

    def __exit__(self, exc_type, exc_value, traceback):
        if self.file is not None:
            self.file.close()

# 使用上下文管理器
with MyFileContext('example.txt') as file:
    content = file.read()
    print(content)
# 当 with 语句块执行完毕后,MyFileContext 的 __exit__ 方法会被调用,从而关闭文件

成员属性相关

__getattribute__
  • 作用说明: 获取一个属性的值。如果属性不存在,并且没有定义__getattr__ 方法,则会引发AttributeError异常
  • 应用场景: 这个方法提供了一种方式来拦截对属性访问的常规过程,允许你添加自定义的逻辑。
  • 触发时机: 当访问对象成员时,自动触发,无论当前成员是否存在
  • 注意事项: 在当前的魔术方法中,禁止使用对象.成员的方式进行成员访问,会触发递归,如果想要在当前魔术方法中访问对象的成员,必须使用object.__getattribute__(self,item)
__getattr__
  • 作用说明: 允许提供一个默认的行为来处理访问不存在的属性;防止访问不存在的成员时报错,也可以为不存在的成员进行赋值操作
  • 触发时机: 当访问对象中不存在的成员时,自动触发
  • 注意事项: 会优先执行__getattribute__方法,不可在当前方法中访问这个不存在的成员,会触发递归
__setattr__
  • 作用说明: 可以限制或管理对象成员的添加和修改操作
  • 触发时机: 当给对象的成员进行赋值操作时自动触发(添加、修改)
  • 方法参数: 1.self接收当前对象、2.设置的成员名、3.设置的成员值
  • 注意事项: 在当前的魔术方法中禁止给当前对象的成员直接进行赋值操作,会触发递归,如果想要给当前对象的成员赋值,必须使用object.__setattr__(self,key,value)
__delattr__
  • 作用说明: 可以限制对象成员的删除,还可以删除不存在的成员时防止报错
  • 触发时机: 当删除对象的成员时自动触发
  • 方法参数: 1.self接收当前、2.item删除的成员名称
  • 注意事项: 在当前的魔术方法中禁止给当前对象的成员直接进行赋值操作,会触发递归,如果想要删除当前对象的成员,必须使用object.__delattr__(self,item)
示例代码
class Person():
    name = '名字'
    age = '年龄'
    sex = '性别'

    def __init__(self,name,age,sex):
        self.name = name
        self.age = age
        self.sex = sex


    def say(self):
        print('聊聊人数,谈谈理想...')

    def sing(self):
        print('高歌一曲,豪放一生...')

    # 获取对象成员时自动触发
    def __getattribute__(self, item):
        print('__getattribute__访问属性:', item)
        # print(self.name)    # 触发递归 重复执行996次  严谨使用self当前对象
        # 通过try来实现判断访问的属性是否存在
        try:
            # 在方法中使用object来获取属性值
            res = object.__getattribute__(self,item)
            return res[0] + '*' + res[-1]
        except:
            return False

    # 当访问不存在的成员时自动触发
    def __getattr__(self, item):
        print('__getattr__访问属性:',item)
        return False

    # 当给对象成员进行赋值时触发,该方法中如果没有给对象成员赋值,那么赋值失败
    def __setattr__(self, key, value):
        print('__setattr__访问属性:', self, key, value)
        object.__setattr__(self, key, value)

    # 当删除对象的成员时自动触发
    def __delattr__(self, item):
        print('__delattr__访问属性:',item)
        object.__delattr__(self,item)


zsf = Person('张三疯',18,'男')
print(zsf.name)
print(zsf.abc)
zsf.abc = 'aabbcc'
print(zsf.abc)
del zsf.abc
print(zsf.abc)

容器相关

操作魔术方法意义
a[key]=value__setitem__(self, key, value)赋值操作
a[item]__getitem__(self, item)索引操作
del a[key]__delitem__(self, key)删除元素
len(a)__len__(self)容器长度
in/not in__contains__(self, item)是否包含某个元素
reversed()__reversed__(self)反转容器
__setitem__
  • 作用说明: 用于设置容器中指定索引位置的元素值
  • 触发时机: 当使用索引操作符[]来设置容器中的元素时触发
class MyContainer:
    def __init__(self):
        self.items = []

    def __setitem__(self, index, value):
        self.items[index] = value

container = MyContainer()
container[0] = 10  # 设置容器中索引为0的元素为10
print(container.items)  # 输出:[10]
__getitem__
  • 作用说明: 获取容器中指定索引位置的元素
  • 触发时机: 当使用索引操作符[]来访问容器中的元素时
class MyContainer:
    def __init__(self):
        self.items = []

    def __getitem__(self, index):
        return self.items[index]

container = MyContainer()
container.items.append(10)
print(container[0])  # 输出:10
__delitem__
  • 作用说明: 删除容器中指定索引位置的元素
  • 触发时机: 当使用 del 语句来删除容器中的元素时
class MyContainer:
    def __init__(self):
        self.items = []

    def __delitem__(self, index):
        del self.items[index]

container = MyContainer()
container.items.append(10)
del container[0]  # 删除容器中索引为0的元素
print(container.items)  # 输出:[]
__contains__
  • 作用说明: 检查容器中是否包含特定的元素
  • 触发时机: 当使用in关键字来检查一个元素是否是容器的成员时
class MyContainer:
    def __init__(self):
        self.items = []

    def __contains__(self, item):
        return item in self.items

container = MyContainer()
container.items.append(10)
print(10 in container)  # 输出:True

迭代器

__iter__
  • 作用说明: 返回一个迭代器对象,该对象定义了迭代过程中所需的__next__方法。当对类实例使用for...in循环时,Python会首先调用__iter__方法来获取迭代器,然后反复调用迭代器的__next__方法来遍历元素
  • 应用场景: 当想要一个类的实例能够被迭代时,需要实现__iter__方法。
class MyIterator:
    def __init__(self, start, end):
        self.value = start
        self.end = end

    def __iter__(self):
        return self  # 返回迭代器本身

    def __next__(self):
        if self.value >= self.end:
            raise StopIteration
        current_value = self.value
        self.value += 1
        return current_value

my_iter = MyIterator(0, 3)
for i in my_iter:
    print(i)  # 输出 0, 1, 2
__next__
  • 作用说明: 返回迭代器中的下一个元素。当迭代器中的所有元素都被访问过后,该方法应该抛出一个StopIteration异常来通知for...in循环停止
  • 应用场景: 通常不直接在自定义类中实现,而是在实现__iter__方法的迭代器类中实现。这个方法用于返回迭代器的下一个元素。
class MyIterator:
    def __init__(self, start, end):
        self.value = start
        self.end = end

    def __iter__(self):
        return self  # 返回迭代器本身

    def __next__(self):
        if self.value >= self.end:
            raise StopIteration
        current_value = self.value
        self.value += 1
        return current_value

my_iter = MyIterator(0, 3)
for i in my_iter:
    print(i)  # 输出 0, 1, 2

比较相关

__eq__
  • 作用说明: 定义了对象之间的相等比较逻辑。它应该返回一个布尔值,指示调用对象是否等于另一个对象。
  • 应用场景: 当想自定义对象之间的等于(==)比较行为时,需要实现 __eq__ 方法。
  • 触发时机: 当使用等于运算符==比较两个对象时,__eq__ 方法会被触发。
class MyClass:
    def __init__(self, value):
        self.value = value

    def __gt__(self, other):
        return self.value > other.value

a = MyClass(5)
b = MyClass(3)
print(a > b)  # 输出:True
__ne__
  • 作用说明: 定义了对象之间的不等于比较逻辑。它应该返回一个布尔值,指示调用对象是否不等于另一个对象。
  • 应用场景: 当想自定义对象之间的等于(!=)比较行为时,需要实现 __ne__ 方法。
  • 触发时机: 当使用不等于运算符!=比较两个对象时,__ne__ 方法会被触发。
class MyClass:
    def __init__(self, value):
        self.value = value

    def __ne__(self, other):
        return self.value != other.value

a = MyClass(5)
b = MyClass(3)
print(a != b)  # 输出:True
__gt__
  • 作用说明: 定义了对象之间的大于比较逻辑。它应该返回一个布尔值,指示调用对象是否大于另一个对象。
  • 应用场景: 当想自定义对象之间的大于>比较行为时,需要实现__gt__方法。
  • 触发时机: 当使用大于运算符>比较两个对象时,__gt__方法会被触发。
class MyClass:
    def __init__(self, value):
        self.value = value

    def __eq__(self, other):
        return self.value == other.value

a = MyClass(5)
b = MyClass(5)
print(a == b)  # 输出:True
__ge__
  • 作用说明: 定义了对象之间的大于等于比较逻辑。它应该返回一个布尔值,指示调用对象是否大于等于另一个对象。
  • 应用场景: 当想自定义对象之间的大于等于>=比较行为时,需要实现__ge__方法。
  • 触发时机: 当使用大于等于运算符>=比较两个对象时,__ge__方法会被触发。
class MyClass:
    def __init__(self, value):
        self.value = value

    def __ge__(self, other):
        return self.value >= other.value

a = MyClass(5)
b = MyClass(3)
print(a >= b)  # 输出:True
__lt__
  • 作用说明: 定义了对象之间的小于比较逻辑。它应该返回一个布尔值,指示调用对象是否小于另一个对象。
  • 应用场景: 当想自定义对象之间的小于 < 比较行为时,需要实现__lt__方法。
  • 触发时机: 当使用小于运算符 < 比较两个对象时,__lt__方法会被触发。
class MyClass:
    def __init__(self, value):
        self.value = value

    def __lt__(self, other):
        return self.value < other.value

a = MyClass(5)
b = MyClass(3)
print(a < b)  # 输出:False
__le__
  • 作用说明: 定义了对象之间的小于等于比较逻辑。它应该返回一个布尔值,指示调用对象是否小于等于另一个对象。
  • 应用场景: 当想自定义对象之间的小于等于 <= 比较行为时,需要实现__le__方法。
  • 触发时机: 当使用小于等于运算符 <= 比较两个对象时,__le__方法会被触发。
class MyClass:
    def __init__(self, value):
        self.value = value

    def __le__(self, other):
        return self.value <= other.value

a = MyClass(5)
b = MyClass(5)
print(a <= b)  # 输出:True

运算相关

运算符魔术方法意义
+add
-sub
*mul
/truediv
//floordiv向下取整
%mod取余
**pow乘方
__add__
  • 作用说明: 定义了对象之间的加法运算行为
  • 应用场景: 当希望类的实例支持加法运算时,需要实现__add__方法
  • 触发时机: 当使用加法运算符+将两个对象相加时,__add__方法会被触发
class MyNumber:
    def __init__(self, value):
        self.value = value

    def __add__(self, other):
        if isinstance(other, MyNumber):
            return MyNumber(self.value + other.value)
        else:
            raise TypeError("Unsupported operand type for +")

a = MyNumber(5)
b = MyNumber(3)
c = a + b  # 触发 __add__ 方法
print(c.value)  # 输出:8
__sub__
  • 作用说明: 定义了对象之间的减法运算行为
  • 应用场景: 当希望类的实例支持减法运算时,需要实现__sub__方法
  • 触发时机: 当使用减法运算符-将两个对象相减时,__sub__方法会被触发
class MyNumber:
    def __init__(self, value):
        self.value = value

    def __sub__(self, other):
        if isinstance(other, MyNumber):
            return MyNumber(self.value - other.value)
        else:
            raise TypeError("Unsupported operand type for -")

a = MyNumber(5)
b = MyNumber(3)
c = a - b  # 触发 __sub__ 方法
print(c.value)  # 输出:2
__mul__
  • 作用说明: 定义了对象之间的乘法运算行为
  • 应用场景: 当希望类的实例支持乘法运算时,需要实现__mul__方法
  • 触发时机: 当使用乘法运算符*将两个对象相乘时,__mul__方法会被触发
class MyNumber:
    def __init__(self, value):
        self.value = value

    def __mul__(self, other):
        if isinstance(other, MyNumber):
            return MyNumber(self.value * other.value)
        else:
            raise TypeError("Unsupported operand type for *")

a = MyNumber(5)
b = MyNumber(3)
c = a * b  # 触发 __mul__ 方法
print(c.value)  # 输出:15
__truediv__
  • 作用说明: 定义了对象之间的除法运算行为
  • 应用场景: 当希望类的实例支持除法运算时,需要实现__truediv__方法
  • 触发时机: 当使用乘法运算符 / 将两个对象相除时,__truediv__方法会被触发
class CustomNumber:
    def __init__(self, value):
        self.value = value

    def __truediv__(self, other):
        if isinstance(other, CustomNumber):
            return CustomNumber(self.value / other.value)
        else:
            raise TypeError("Unsupported operand type for /")

a = CustomNumber(10)
b = CustomNumber(2)
c = a / b  # 触发 __truediv__ 方法
print(c.value)  # 输出:5.0
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

需要休息的KK.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值