36、Python 类扩展与高级应用技巧

Python 类扩展与高级应用技巧

1. 类扩展之 Mixin 模式

在编程中,有时我们有一组有用的方法,希望在不同类中复用,以扩展其功能,但这些类之间可能没有继承关系,不能简单地将方法附加到一个公共基类上。这时,Mixin 模式就派上用场了。

1.1 Mixin 类的定义

以下是几个示例 Mixin 类:

class LoggedMappingMixin:
    '''
    添加 get/set/delete 操作的日志记录,用于调试。
    '''
    __slots__ = ()

    def __getitem__(self, key):
        print('Getting ' + str(key))
        return super().__getitem__(key)

    def __setitem__(self, key, value):
        print('Setting {} = {!r}'.format(key, value))
        return super().__setitem__(key, value)

    def __delitem__(self, key):
        print('Deleting ' + str(key))
        return super().__delitem__(key)


class SetOnceMappingMixin:
    '''
    允许键只设置一次。
    '''
    __slots__ = ()

    def __setitem__(self, key, value):
        if key in self:
            raise KeyError(str(key) + ' already set')
        return super().__setitem__(key, value)


class StringKeysMappingMixin:
    '''
    禁止键为字符串以外的类型。
    '''
    __slots__ = ()

    def __setitem__(self, key, value):
        if not isinstance(key, str):
            raise TypeError('keys must be strings')
        return super().__setitem__(key, value)

这些 Mixin 类本身单独使用没有太大意义,需要通过多重继承混入其他类中。

1.2 Mixin 类的使用示例
class LoggedDict(LoggedMappingMixin, dict):
    pass


d = LoggedDict()
d['x'] = 23
# 输出: Setting x = 23
d['x']
# 输出: Getting x
# 输出: 23
del d['x']
# 输出: Deleting x

从这个示例可以看出,Mixin 类与现有的类(如 dict )结合使用,共同提供所需的功能。

1.3 Mixin 类的注意事项
  • 不能直接创建实例 :Mixin 类不是为了直接创建实例而设计的,它们需要混入到其他实现所需功能的类中。
  • 通常无自身状态 :Mixin 类一般没有 __init__() 方法和实例变量, __slots__ = () 明确表示它们没有自己的实例数据。如果要定义有 __init__() 方法和实例变量的 Mixin 类,需要注意变量名避免冲突,并且 __init__() 方法要正确调用其他类的 __init__() 方法。
  • super() 的使用 super() 是编写 Mixin 类的关键,它将方法调用委托给方法解析顺序(MRO)中的下一个类。例如,在 LoggedMappingMixin 中使用 super().__getitem__() 实际上会调用 dict.__getitem__()
1.4 装饰器实现 Mixin

除了多重继承,还可以使用装饰器实现类似 Mixin 的功能。

def LoggedMapping(cls):
    cls_getitem = cls.__getitem__
    cls_setitem = cls.__setitem__
    cls_delitem = cls.__delitem__

    def __getitem__(self, key):
        print('Getting ' + str(key))
        return cls_getitem(self, key)

    def __setitem__(self, key, value):
        print('Setting {} = {!r}'.format(key, value))
        return cls_setitem(self, key, value)

    def __delitem__(self, key):
        print('Deleting ' + str(key))
        return cls_delitem(self, key)

    cls.__getitem__ = __getitem__
    cls.__setitem__ = __setitem__
    cls.__delitem__ = __delitem__
    return cls


@LoggedMapping
class LoggedDict(dict):
    pass

这种方式不使用多重继承,而是通过装饰器对类定义进行修改,替换部分方法。

2. 实现状态对象或有限状态机

在某些应用中,我们需要根据对象的内部状态执行不同的操作,但又不想让代码被大量的条件判断所充斥。这时可以采用将每个操作状态编码为单独的类,让主类将操作委托给状态类的方法。

2.1 简单实现
class Connection:
    def __init__(self):
        self.new_state(ClosedConnectionState)

    def new_state(self, newstate):
        self._state = newstate

    # 委托给状态类
    def read(self):
        return self._state.read(self)

    def write(self, data):
        return self._state.write(self, data)

    def open(self):
        return self._state.open(self)

    def close(self):
        return self._state.close(self)


# 连接状态基类
class ConnectionState:
    @staticmethod
    def read(conn):
        raise NotImplementedError()

    @staticmethod
    def write(conn, data):
        raise NotImplementedError()

    @staticmethod
    def open(conn):
        raise NotImplementedError()

    @staticmethod
    def close(conn):
        raise NotImplementedError()


# 关闭连接状态
class ClosedConnectionState(ConnectionState):
    @staticmethod
    def read(conn):
        raise RuntimeError('Not open')

    @staticmethod
    def write(conn, data):
        raise RuntimeError('Not open')

    @staticmethod
    def open(conn):
        conn.new_state(OpenConnectionState)

    @staticmethod
    def close(conn):
        raise RuntimeError('Already closed')


# 打开连接状态
class OpenConnectionState(ConnectionState):
    @staticmethod
    def read(conn):
        print('reading')

    @staticmethod
    def write(conn, data):
        print('writing')

    @staticmethod
    def open(conn):
        raise RuntimeError('Already open')

    @staticmethod
    def close(conn):
        conn.new_state(ClosedConnectionState)


c = Connection()
print(c._state)
# 输出: <class '__main__.ClosedConnectionState'>
try:
    c.read()
except RuntimeError as e:
    print(e)
# 输出: Not open
c.open()
print(c._state)
# 输出: <class '__main__.OpenConnectionState'>
c.read()
# 输出: reading
c.write('hello')
# 输出: writing
c.close()
print(c._state)
# 输出: <class '__main__.ClosedConnectionState'>

这个实现将不同的连接状态封装在不同的类中,避免了大量的条件判断,使代码更易于维护和理解。

2.2 直接操作 __class__ 属性的实现
class Connection:
    def __init__(self):
        self.new_state(ClosedConnection)

    def new_state(self, newstate):
        self.__class__ = newstate

    def read(self):
        raise NotImplementedError()

    def write(self, data):
        raise NotImplementedError()

    def open(self):
        raise NotImplementedError()

    def close(self):
        raise NotImplementedError()


class ClosedConnection(Connection):
    def read(self):
        raise RuntimeError('Not open')

    def write(self, data):
        raise RuntimeError('Not open')

    def open(self):
        self.new_state(OpenConnection)

    def close(self):
        raise RuntimeError('Already closed')


class OpenConnection(Connection):
    def read(self):
        print('reading')

    def write(self, data):
        print('writing')

    def open(self):
        raise RuntimeError('Already open')

    def close(self):
        self.new_state(ClosedConnection)


c = Connection()
print(c)
# 输出: <__main__.ClosedConnection object at ...>
try:
    c.read()
except RuntimeError as e:
    print(e)
# 输出: Not open
c.open()
print(c)
# 输出: <__main__.OpenConnection object at ...>
c.read()
# 输出: reading
c.close()
print(c)
# 输出: <__main__.ClosedConnection object at ...>

这种实现方式消除了额外的间接层,当状态改变时,实例直接改变其类型。虽然可能会让一些纯面向对象编程者不满,但技术上是可行的,并且可能会提高程序的执行效率。

3. 调用对象方法(传入方法名作为字符串)

有时候我们需要根据字符串形式的方法名调用对象的方法,有两种常见的实现方式。

3.1 使用 getattr()
import math


class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return 'Point({!r:},{!r:})'.format(self.x, self.y)

    def distance(self, x, y):
        return math.hypot(self.x - x, self.y - y)


p = Point(2, 3)
d = getattr(p, 'distance')(0, 0)
print(d)

这种方式通过 getattr() 查找对象的属性(方法),然后将其作为函数调用。

3.2 使用 operator.methodcaller()
import operator

points = [
    Point(1, 2),
    Point(3, 0),
    Point(10, -3),
    Point(-5, -7),
    Point(-1, 8),
    Point(3, 2)
]

# 按到 (0, 0) 的距离排序
points.sort(key=operator.methodcaller('distance', 0, 0))
print(points)

operator.methodcaller() 创建一个可调用对象,并固定方法的参数,方便多次使用相同参数调用方法。

4. 实现访问者模式

当需要处理复杂的数据结构,且其中的不同类型对象需要不同的处理方式时,访问者模式是一个很好的解决方案。

4.1 数据结构的定义
class Node:
    pass


class UnaryOperator(Node):
    def __init__(self, operand):
        self.operand = operand


class BinaryOperator(Node):
    def __init__(self, left, right):
        self.left = left
        self.right = right


class Add(BinaryOperator):
    pass


class Sub(BinaryOperator):
    pass


class Mul(BinaryOperator):
    pass


class Div(BinaryOperator):
    pass


class Negate(UnaryOperator):
    pass


class Number(Node):
    def __init__(self, value):
        self.value = value


# 表示 1 + 2 * (3 - 4) / 5
t1 = Sub(Number(3), Number(4))
t2 = Mul(Number(2), t1)
t3 = Div(t2, Number(5))
t4 = Add(Number(1), t3)
4.2 访问者类的实现
class NodeVisitor:
    def visit(self, node):
        methname = 'visit_' + type(node).__name__
        meth = getattr(self, methname, None)
        if meth is None:
            meth = self.generic_visit
        return meth(node)

    def generic_visit(self, node):
        raise RuntimeError('No {} method'.format('visit_' + type(node).__name__))


class Evaluator(NodeVisitor):
    def visit_Number(self, node):
        return node.value

    def visit_Add(self, node):
        return self.visit(node.left) + self.visit(node.right)

    def visit_Sub(self, node):
        return self.visit(node.left) - self.visit(node.right)

    def visit_Mul(self, node):
        return self.visit(node.left) * self.visit(node.right)

    def visit_Div(self, node):
        return self.visit(node.left) / self.visit(node.right)

    def visit_Negate(self, node):
        return -node.operand


e = Evaluator()
result = e.visit(t4)
print(result)
# 输出: 0.6

访问者模式将数据结构的操作与数据结构本身分离,提高了代码的通用性。通过动态生成方法名并使用 getattr() 获取方法,避免了大量的 if 语句,使代码更易于维护。

5. 无递归实现访问者模式

在处理深度嵌套的数据结构时,递归实现的访问者模式可能会达到 Python 的递归限制。可以使用生成器和栈来消除递归。

5.1 无递归访问者类的实现
import types


class Node:
    pass


class NodeVisitor:
    def visit(self, node):
        stack = [node]
        last_result = None
        while stack:
            try:
                last = stack[-1]
                if isinstance(last, types.GeneratorType):
                    stack.append(last.send(last_result))
                    last_result = None
                elif isinstance(last, Node):
                    stack.append(self._visit(stack.pop()))
                else:
                    last_result = stack.pop()
            except StopIteration:
                stack.pop()
        return last_result

    def _visit(self, node):
        methname = 'visit_' + type(node).__name__
        meth = getattr(self, methname, None)
        if meth is None:
            meth = self.generic_visit
        return meth(node)

    def generic_visit(self, node):
        raise RuntimeError('No {} method'.format('visit_' + type(node).__name__))


class Evaluator(NodeVisitor):
    def visit_Number(self, node):
        return node.value

    def visit_Add(self, node):
        yield (yield node.left) + (yield node.right)

    def visit_Sub(self, node):
        yield (yield node.left) - (yield node.right)

    def visit_Mul(self, node):
        yield (yield node.left) * (yield node.right)

    def visit_Div(self, node):
        yield (yield node.left) / (yield node.right)

    def visit_Negate(self, node):
        yield - (yield node.operand)


a = Number(0)
for n in range(1, 100000):
    a = Add(a, Number(n))

e = Evaluator()
result = e.visit(a)
print(result)

这种实现利用生成器的 yield 特性,将节点发送回 visit() 方法进行处理,避免了递归调用,解决了递归深度限制的问题。

6. 循环数据结构的内存管理

在处理循环数据结构(如树、图等)时,Python 的垃圾回收机制可能会出现问题,因为循环引用会导致对象的引用计数永远不为 0。可以使用 weakref 库创建弱引用解决这个问题。

6.1 弱引用的使用示例
import weakref


class Node:
    def __init__(self, value):
        self.value = value
        self._parent = None
        self.children = []

    def __repr__(self):
        return 'Node({!r:})'.format(self.value)

    @property
    def parent(self):
        return self._parent if self._parent is None else self._parent()

    @parent.setter
    def parent(self, node):
        self._parent = weakref.ref(node)

    def add_child(self, child):
        self.children.append(child)
        child.parent = self


root = Node('parent')
c1 = Node('child')
root.add_child(c1)
print(c1.parent)
# 输出: Node('parent')
del root
print(c1.parent)
# 输出: None

弱引用不会增加对象的引用计数,当对象的其他引用消失时,对象可以被正常垃圾回收。

7. 让类支持比较操作

如果希望类的实例能够使用常见的比较运算符(如 >= , != , <= 等),可以使用 functools.total_ordering 装饰器简化实现。

7.1 示例代码
from functools import total_ordering


class Room:
    def __init__(self, name, length, width):
        self.name = name
        self.length = length
        self.width = width
        self.square_feet = self.length * self.width


@total_ordering
class House:
    def __init__(self, name, style):
        self.name = name
        self.style = style
        self.rooms = list()

    @property
    def living_space_footage(self):
        return sum(r.square_feet for r in self.rooms)

    def add_room(self, room):
        self.rooms.append(room)

    def __str__(self):
        return '{}: {} square foot {}'.format(self.name,
                                              self.living_space_footage,
                                              self.style)

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

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


h1 = House('h1', 'Cape')
h1.add_room(Room('Master Bedroom', 14, 21))
h1.add_room(Room('Living Room', 18, 20))
h1.add_room(Room('Kitchen', 12, 16))
h1.add_room(Room('Office', 12, 12))

h2 = House('h2', 'Ranch')
h2.add_room(Room('Master Bedroom', 14, 21))
h2.add_room(Room('Living Room', 18, 20))
h2.add_room(Room('Kitchen', 12, 16))

h3 = House('h3', 'Split')
h3.add_room(Room('Master Bedroom', 14, 21))
h3.add_room(Room('Living Room', 18, 20))
h3.add_room(Room('Office', 12, 16))
h3.add_room(Room('Kitchen', 15, 17))

houses = [h1, h2, h3]

print('Is h1 bigger than h2?', h1 > h2)
print('Is h2 smaller than h3?', h2 < h3)
print('Is h2 greater than or equal to h1?', h2 >= h1)
print('Which one is biggest?', max(houses))
print('Which is smallest?', min(houses))

total_ordering 装饰器根据定义的 __eq__() 和一个比较方法(如 __lt__() )自动生成其他比较方法,减少了手动编写大量比较方法的工作量。

8. 创建缓存实例

在创建类的实例时,有时希望对于相同的参数返回缓存的实例引用。

8.1 简单缓存实现
# 被查询的类
class Spam:
    def __init__(self, name):
        self.name = name


# 支持缓存
import weakref

_spam_cache = weakref.WeakValueDictionary()


def get_spam(name):
    if name not in _spam_cache:
        s = Spam(name)
        _spam_cache[name] = s
    else:
        s = _spam_cache[name]
    return s


a = get_spam('foo')
b = get_spam('bar')
c = get_spam('foo')
print(a is c)
# 输出: True

使用 WeakValueDictionary 作为缓存,当实例不再被使用时,缓存中的引用会自动消失,避免了内存泄漏。

8.2 更完善的实现

可以将缓存代码封装在一个管理类中,提高代码的可维护性和灵活性。

import weakref


class CachedSpamManager:
    def __init__(self):
        self._cache = weakref.WeakValueDictionary()

    def get_spam(self, name):
        if name not in self._cache:
            s = Spam(name)
            self._cache[name] = s
        else:
            s = self._cache[name]
        return s

    def clear(self):
        self._cache.clear()


class Spam:
    manager = CachedSpamManager()

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

    @classmethod
    def get_spam(cls, name):
        return cls.manager.get_spam(name)


a = Spam.get_spam('foo')
b = Spam.get_spam('bar')
c = Spam.get_spam('foo')
print(a is c)
# 输出: True

这种实现方式将缓存逻辑封装在 CachedSpamManager 类中,方便对缓存进行管理和扩展。同时,可以通过一些方式限制用户直接创建实例,避免绕过缓存机制。

综上所述,Python 提供了多种高级技巧来扩展类的功能、处理复杂的数据结构和优化代码性能。合理运用这些技巧可以使代码更加健壮、高效和易于维护。

Python 类扩展与高级应用技巧

9. 各类技巧总结与对比

为了更清晰地理解上述各种 Python 高级技巧,下面通过表格进行总结对比:
| 技巧名称 | 主要用途 | 实现方式 | 优点 | 缺点 |
| — | — | — | — | — |
| Mixin 模式 | 复用方法扩展类功能 | 多重继承或装饰器 | 提高代码复用性,降低耦合度 | 可能导致类继承关系复杂 |
| 状态机模式 | 处理对象不同状态下的操作 | 状态类委托或操作 __class__ 属性 | 避免大量条件判断,代码易维护 | 可能不符合纯面向对象编程理念 |
| 字符串调用方法 | 根据字符串方法名调用对象方法 | getattr() operator.methodcaller() | 灵活调用方法 | 可能增加代码理解难度 |
| 访问者模式 | 处理复杂数据结构中不同类型对象 | 动态生成方法名并使用 getattr() | 分离操作与数据结构,代码通用 | 递归实现可能达到递归限制 |
| 无递归访问者模式 | 解决深度嵌套数据结构递归限制问题 | 生成器和栈 | 避免递归深度限制 | 实现逻辑较复杂 |
| 循环数据结构内存管理 | 解决循环引用导致的内存回收问题 | weakref 库创建弱引用 | 避免内存泄漏 | 增加代码复杂度 |
| 类比较操作支持 | 让类实例支持常见比较运算符 | functools.total_ordering 装饰器 | 减少手动编写比较方法工作量 | 依赖装饰器 |
| 创建缓存实例 | 相同参数返回缓存实例引用 | 缓存字典或管理类 | 避免重复创建实例,节省内存 | 可能增加代码复杂度和维护成本 |

10. 实际应用场景分析

这些高级技巧在实际项目中有广泛的应用场景,以下是一些具体示例:

10.1 Web 开发
  • Mixin 模式 :在 Django 框架中,可以使用 Mixin 模式为视图类添加额外的功能,如权限验证、日志记录等。
from django.views.generic import View

class LoggedViewMixin:
    def dispatch(self, request, *args, **kwargs):
        print(f"Request received: {request.path}")
        return super().dispatch(request, *args, **kwargs)

class MyView(LoggedViewMixin, View):
    def get(self, request):
        return HttpResponse("Hello, World!")
  • 访问者模式 :在处理复杂的表单数据时,访问者模式可以将数据验证和处理逻辑分离,提高代码的可维护性。
10.2 游戏开发
  • 状态机模式 :游戏角色的状态管理,如站立、行走、攻击等状态,可以使用状态机模式进行实现,使角色状态转换逻辑清晰。
class Character:
    def __init__(self):
        self.state = StandingState()

    def change_state(self, new_state):
        self.state = new_state

    def action(self):
        self.state.action(self)

class StandingState:
    def action(self, character):
        print("Character is standing.")

class WalkingState:
    def action(self, character):
        print("Character is walking.")
  • 创建缓存实例 :游戏中的一些资源,如纹理、音效等,可以使用缓存实例的方式,避免重复加载,提高游戏性能。
11. 技巧使用建议与注意事项

在使用这些高级技巧时,需要注意以下几点:

11.1 Mixin 模式
  • 避免 Mixin 类之间的依赖关系过于复杂,否则会导致代码难以理解和维护。
  • 确保 Mixin 类的方法名不会与其他类的方法名冲突。
11.2 状态机模式
  • 状态类的设计要合理,避免状态类过多导致代码膨胀。
  • 在操作 __class__ 属性时,要确保不会引发意外的错误。
11.3 字符串调用方法
  • 要确保传入的字符串方法名是合法的,否则会引发 AttributeError 异常。
  • 尽量避免在性能敏感的代码中使用,因为字符串查找和方法调用会有一定的开销。
11.4 访问者模式
  • 递归实现时要注意 Python 的递归限制,可以考虑使用无递归实现。
  • 当数据结构发生变化时,可能需要修改访问者类的实现。
11.5 无递归访问者模式
  • 理解生成器和栈的工作原理,确保代码逻辑正确。
  • 处理不同类型的返回值时要小心,避免出现意外错误。
11.6 循环数据结构内存管理
  • 正确使用 weakref 库,避免引入新的内存泄漏问题。
  • 注意弱引用的生命周期,确保在需要时对象仍然存在。
11.7 类比较操作支持
  • 确保定义的 __eq__() 和比较方法逻辑正确,否则会导致比较结果错误。
  • 装饰器生成的方法可能会影响代码的可读性,需要适当添加注释。
11.8 创建缓存实例
  • 合理设计缓存的过期策略,避免缓存数据过时。
  • 注意缓存的并发访问问题,确保线程安全。
12. 未来发展趋势与展望

随着 Python 语言的不断发展,这些高级技巧也可能会有新的变化和应用。

12.1 语言特性的增强

Python 可能会引入更多的语言特性来简化这些高级技巧的实现。例如,未来可能会有更简洁的方式来实现 Mixin 模式或状态机模式。

12.2 与其他技术的融合

这些技巧可能会与其他技术,如机器学习、大数据等进行更深入的融合。例如,在处理大规模数据时,使用访问者模式可以更高效地对数据进行处理和分析。

12.3 代码自动化工具的发展

可能会出现更多的代码自动化工具,帮助开发者更方便地使用这些高级技巧。例如,自动生成 Mixin 类或状态机类的工具。

13. 总结

Python 中的这些高级技巧为开发者提供了强大的工具,能够处理各种复杂的编程场景。通过合理运用 Mixin 模式、状态机模式、访问者模式等技巧,可以提高代码的复用性、可维护性和性能。同时,在使用这些技巧时,要注意各种注意事项,避免引入不必要的问题。随着 Python 语言的发展,这些技巧也将不断演变和完善,为开发者带来更多的便利。

附录:部分技巧的流程图

13.1 无递归访问者模式流程图
graph TD;
    A[开始] --> B[初始化栈和结果变量];
    B --> C{栈是否为空};
    C -- 否 --> D{栈顶元素类型};
    D -- 生成器 --> E[发送结果并添加新元素到栈];
    E --> F[清空结果变量];
    F --> C;
    D -- 节点 --> G[调用对应方法并添加结果到栈];
    G --> C;
    D -- 其他 --> H[弹出栈顶元素作为结果];
    H --> C;
    C -- 是 --> I[返回最终结果];
13.2 创建缓存实例流程图
graph TD;
    A[创建实例请求] --> B{参数是否在缓存中};
    B -- 是 --> C[返回缓存实例];
    B -- 否 --> D[创建新实例];
    D --> E[将新实例存入缓存];
    E --> F[返回新实例];

通过以上的介绍和分析,相信你对 Python 的这些高级技巧有了更深入的理解。在实际编程中,可以根据具体的需求选择合适的技巧,提高代码的质量和性能。

【无人机】基于改进粒子群算法的无人机路径规划研究[和遗传算法、粒子群算法进行比较](Matlab代码实现)内容概要:本文围绕基于改进粒子群算法的无人机路径规划展开研究,重点探讨了在复杂环境中利用改进粒子群算法(PSO)实现无人机三维路径规划的方法,并将其遗传算法(GA)、标准粒子群算法等传统优化算法进行对比分析。研究内容涵盖路径规划的多目标优化、避障策略、航路点约束以及算法收敛性和寻优能力的评估,所有实验均通过Matlab代码实现,提供了完整的仿真验证流程。文章还提到了多种智能优化算法在无人机路径规划中的应用比较,突出了改进PSO在收敛速度和全局寻优方面的优势。; 适合人群:具备一定Matlab编程基础和优化算法知识的研究生、科研人员及从事无人机路径规划、智能优化算法研究的相关技术人员。; 使用场景及目标:①用于无人机在复杂地形或动态环境下的三维路径规划仿真研究;②比较不同智能优化算法(如PSO、GA、蚁群算法、RRT等)在路径规划中的性能差异;③为多目标优化问题提供算法选型和改进思路。; 阅读建议:建议读者结合文中提供的Matlab代码进行实践操作,重点关注算法的参数设置、适应度函数设计及路径约束处理方式,同时可参考文中提到的多种算法对比思路,拓展到其他智能优化算法的研究改进中。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值