Python静态类型检查

第一章、PEP

一、概述

PEP 是 Python Enhancement Proposal(Python 增强建议书)的缩写,它是用于提出、讨论和记录 Python 语言改进的技术文档。PEP 主要用于讨论 Python 语言的新特性、语法改进、标准库的变化、以及任何其他与 Python 语言相关的议题。PEP 提案可以由 Python 社区中的任何人提交,并且会经过讨论、审查和最终投票来确定是否接受该提案。

每个 PEP 文档都有一个唯一的编号,并且遵循一定的格式和结构。PEP 文档通常包括以下几个部分:

  1. PEP 编号:一个唯一的标识符,用于标识特定的 PEP 提案。

  2. 标题:简明扼要地描述该提案的主题或内容。

  3. 作者:列出了该 PEP 提案的作者信息。

  4. 状态:指示该 PEP 提案的状态,如草案(Draft)、接受(Accepted)、拒绝(Rejected)等。

  5. 摘要:对该提案的简要概述,包括提案的动机、目标和设计。

  6. 动机:详细说明该提案的背景和动机,以及为什么需要引入该提案中描述的改进。

  7. 提案内容:具体阐述该提案的技术细节和实施方案。

  8. 相关链接:提供了与该提案相关的其他文档、资源或链接。

通过使用 PEP,Python 社区中的开发者可以就 Python 语言的改进和发展进行讨论和决策。PEP 提案的讨论过程是公开的,任何人都可以参与其中,这使得 Python 的发展更加开放透明。通常,只有经过广泛讨论和投票通过的 PEP 提案才会被采纳并纳入 Python 语言的官方版本中。

第二章、基本类型提示

一、概述

        在Python中,类型提示(Type Hints)是一种用于指示函数和变量预期类型的注释机制。类型提示不会影响代码的运行,但它们提供了对代码阅读者和IDE工具有用的信息,使得代码更易于理解和维护。类型提示首先在PEP 484中被引入,并在PEP 526和PEP 563中进一步扩展和改进。

        类型提示是 Python 3.5 版本引入的一项功能,它允许开发者在变量、函数参数、函数返回值等位置添加类型注释信息,以指定变量和函数的预期类型。尽管 Python 是一种动态类型语言,但类型提示可以提供对代码更多的文档信息,使得代码更易于阅读、理解和维护。

        类型提示的目的是增加代码的可读性和可维护性,以及在静态类型检查工具(如mypy)中进行类型检查。

二、基本语法

在Python中,类型提示使用冒号(:)来指定变量或函数的类型,并使用箭头(->)指定函数的返回类型。

1、变量类型提示

可以在变量声明时使用类型提示

name: str = "John"
age: int = 30
is_student: bool = True

2、函数类型提示

可以在函数参数列表中使用类型提示,可以在函数定义的 -> 后面使用类型提示指定返回值类型

def add(x: int, y: int) -> int:
    return x + y

在这个例子中,函数add接收两个整数类型的参数xy,并返回一个整数类型。

三、单一数据类型可以直接用作类型提示

        在 Python 中,一些内置的基本数据类型,如 strintfloat 等,可以直接用作类型提示,这是因为它们是 Python 的内置类型,具有固定的语法和语义,不需要额外的抽象类来指定。因此,在类型提示中可以直接使用这些内置类型来指定变量的预期类型。

        例如,您可以在类型提示中使用 str 来指定字符串类型,使用 int 来指定整数类型,使用 float 来指定浮点数类型,等等。这些内置类型不需要导入任何模块,因为它们已经是 Python 的一部分。

下面是一些使用内置类型作为类型提示的示例:

name: str = 'John'
age: int = 30
pi: float = 3.14

在这些示例中,strintfloat 都是直接指定预期类型的关键字,用于指定字符串、整数和浮点数类型。由于它们是 Python 的内置类型,因此可以直接用于类型提示而无需额外的导入。

第三章、typing模块

一、概述

typing 模块是 Python 3.5 中引入的一种模块,它提供了对类型提示的支持,用于指定变量、函数参数和返回值的预期类型。它使得 Python 的类型提示更加丰富和灵活,可以指定复杂的数据类型,包括列表、元组、字典等。

二、主要作用

1、丰富的类型提示支持

typing 模块提供了丰富的数据类型,包括但不限于 ListTupleDictSet 等,可以更精确地指定数据的类型。

2、提高代码可读性

通过使用 typing 模块,可以提高代码的可读性和可维护性,使得代码的意图更加清晰

三、提供了一组抽象类,区别与python中的基本类型,用于指定复杂的数据类型,是专门用于类型提示的

typing 模块提供了一组抽象类,用于指定复杂的数据类型,这些抽象类是为了提供对类型提示的支持而设计的。它们用于指定特定类型的数据结构,如列表、元组、字典等,以便提高代码的可读性和可靠性。

与 Python 的基本类型不同,typing 模块中的抽象类并不直接表示实际的数据,而是用于在类型提示中指定预期的数据类型。这些抽象类允许开发者在代码中明确指定变量、函数参数和返回值的预期类型,从而提高了代码的可读性并减少了潜在的类型错误。

使用 typing 模块中的抽象类可以帮助开发者更准确地表达代码的意图,并为代码添加更多的文档信息,从而使得代码更易于理解、维护和扩展

四、常用的类型

typing 模块中,有许多常用的抽象类可用于指定复杂的数据类型。下面是一些常用的类型及其作用的简要说明:

1、List:用于指定列表类型,表示包含指定类型元素的可变序列

from typing import List

my_list: List[int] = [1, 2, 3, 4, 5]

2、Tuple:用于指定元组类型,表示包含指定类型元素的不可变序列

from typing import Tuple

my_tuple: Tuple[int, str, float] = (1, 'two', 3.0)

3、Set:用于指定集合类型,表示包含指定类型元素的无序集合

from typing import Set

my_set: Set[int] = {1, 2, 3, 4, 5}

4、Dict:用于指定字典类型,表示键值对的映射

from typing import Dict

my_dict: Dict[str, int] = {'one': 1, 'two': 2, 'three': 3}

5、Union:用于指定多种可能的类型中的一个,表示多个类型中的任意一个

from typing import Union

def process(value: Union[int, float, str]) -> None:
    # process the value
    pass

#以下三个都是合法的
process(1)
process(3.14)
process("jzq")

6、Any:用于指定任意类型,表示可以是任何类型

from typing import Any

def process_data(data: Any) -> Any:
    # process the data
    return data

除了上述类型之外,typing 模块还提供了许多其他类型,如 OptionalCallableIterableMapping 等,用于指定可选值、可调用对象、可迭代对象、映射对象等。这些抽象类可以帮助开发者更准确地指定预期的数据类型,并提高代码的可读性和可靠性。

第三章、容器类型提示

一、概述

类型提示支持Tuple(元组)、List(列表)、Set(集合)、Dict(字典)等复杂类型

1、又称泛型类型

  • 泛型类型用于表示参数化类型,例如 List[str] 表示字符串类型的列表。
  • 使用方括号 [] 表示参数化类型,如 List[int] 表示整数类型的列表。

2、 必须使用typing模块中的抽象容器类型,不能使用python中的内置容器类型

        在 Python 中,tuple 是一种基本数据类型,表示不可变序列。而 Tupletyping 模块中用于类型提示的抽象类,用于指定特定类型的元组。例如,Tuple[int, str] 表示一个由整数和字符串组成的元组类型。这是一种类型提示的语法,用于指定变量、函数参数或返回值的预期类型。

        因此,虽然它们看起来很相似,但 tuple 是一种具体的数据类型,而 Tuple 是用于类型提示的抽象类。它们在语义上有所不同,并且用途也不同。

        在 Python 中,Tupletyping 模块中用于指定元组类型的抽象类,用于类型提示。它表示一个特定类型和长度的元组。而 tuple 是 Python 中的内置类型,表示不可变序列,用于存储任意数量和类型的元素。

        由于 typing 模块是专门用于提供对复杂数据类型的类型提示支持的,因此它提供了一系列用于指定特定数据类型的抽象类,例如 ListTupleDict 等。这些抽象类可以用于指定预期的数据类型,以便提高代码的可读性和可靠性。

当您需要指定一个特定类型和长度的元组时,可以使用 Tuple 类型提示。例如:

from typing import Tuple

my_tuple: Tuple[int, str, float] = (1, 'two', 3.0)

tuple 并不是用于类型提示的抽象类,它是一种具体的数据类型,在类型提示中使用它是没有意义的。因此,您应该使用 Tuple 类来指定预期的元组类型,而不是使用 tuple。 

二、语法

容器类型[ 容器中元素类型 ]

  • 容器类型可为:Tuple,Dict,List,Set
  • 元素类型可以:任意数据类型

1、对于可变类型容器(指定元素类型,不指定数量

在类型提示中,对于可变的容器类型如列表(List)、集合(Set)字典(Dict)等,只需要指定容器中元素的类型即可,不需要特别指定容器的长度或元素的数量。

例如,对于一个整数类型的列表,可以使用 List[int] 来指定:

2、对于不可变类型容器(指定元素类型及数量

对于不可变的容器类型如元组(Tuple),除了指定元素的类型之外,还需要指定元组中元素的数量。

例如,对于一个包含三个整数的元组,可以使用 Tuple[int, int, int] 来指定:

这种类型提示的规定是为了在代码中提供更多的类型信息,以便类型检查工具能够检测潜在的类型错误,并提高代码的可靠性和可读性。 

三、容器类型总结

1、List[ElementType]

表示列表,其中 ElementType 是列表中元素的类型。

2、Tuple[ElementType1, ElementType2, ...]

表示元组,其中 ElementType1, ElementType2, ... 是元组中元素的类型。

3、Set[ElementType]

表示集合,其中 ElementType 是集合中元素的类型。

4、Dict[KeyType, ValueType]

表示字典,其中 KeyType 是字典中键的类型,ValueType 是字典中值的类型。

第四章、... 类型占位符

一、概述

        在 Python 中,... 是一种特殊的类型占位符,它被用作可变参数的类型提示。它表示一个不确定数量参数的类型,可以用于指定函数接受任意数量的参数。这在编写接受可变数量参数的函数时非常有用。... 类型占位符通常与 Tuple 结合使用,以表示函数接受任意数量的特定类型的参数。

1、...一般只用于在Tuple[数据类型, ...]类型中

...只用于Tuple类型提示中,因为Tuple是不可变容器类型,需要指定元素类型和数量,其他容器类型均不需要指定数量

二、...的作用

1、类型占位符

... 用作一种类型占位符,当容器类型中只有一种类型时,...为该类型占位,否则默认为Any占位,表示为Any

from typing import Tuple

my_tuple: Tuple[int, ...] = (1, 2, 3, 4, 5)

2、可变数量

... 用作表示可变数量,当容器类型中只有一种类型时,...为该类型占位,并表示可变数量,其他情况下均不表示可变数量

from typing import Tuple

def concat(*args: str) -> Tuple[str, ...]:
    return args

result = concat("Hello", "World", "Python")
print(result)  # ('Hello', 'World', 'Python')

 三、只有当Tuple[数据类型, ...] 情况下...表示占位和可变数量,其他情况下均表示为Any占位

为什么Python中Tuple[str,...]和List[str,...]的类型推断不一样尼

在Python中,Tuple[str, ...]List[str, ...]的类型推断之所以不一样,是因为它们在类型提示中代表了不同的含义。

  1. Tuple[str, ...]:

    • Tuple[str, ...]表示一个元素类型为str的元组,并且元组中的元素个数是不确定的,即可以有任意多个元素。
    • 当使用Tuple[str, ...]进行类型注解时,它告诉类型检查工具(如mypy)这是一个元组类型,元组中的元素类型必须是str,但元组的长度可以是任意的,可以包含零个或多个str类型的元素。
    • 例如:('apple', 'banana')('apple', 'banana', 'orange')等都符合Tuple[str, ...]的类型定义。
  2. List[str, ...]:错误的语法

    • 此时...只表示为Any占位,不表示可变数量
    • 例如:['apple', 'banana']['apple', 'banana', 'orange']等都符合List[str, ...]的类型定义。

        所以,虽然Tuple[str, ...]List[str, ...]都使用了...作为占位符,但它们在类型提示中的含义和使用方式是不同的。Tuple[str, ...]表示元组中有不确定数量的str类型元素,而List[str, ...]表示列表中有多个str类型元素,长度固定为多个。

那为什么只有这样 Tuple[Any, ...] 才能表示为任意长度尼

对的,Tuple[Any, ...] 可以表示任意长度的元组,是因为 ...Tuple 类型提示中的特殊含义。... 在这里表示省略号,用来表示一个元组可以包含任意数量的元素,并且每个元素可以是任意类型,这就是为什么 Tuple[Any, ...] 可以表示为任意长度的元组。

Any 是 Python 中表示动态类型的特殊类型,它可以包含任何类型的值,所以 Tuple[Any, ...] 表示一个可以包含任意类型、任意数量元素的元组。

至于其他形式的 Tuple[int, str, ...],目前并没有直接的语法来表示这样的含义,即至少包含一个整数和一个字符串,但可以包含其他类型和任意数量的元素。这种情况下,可以使用 UnionTuple 结合的方式,如下所示:

from typing import Tuple, Union

args: Union[Tuple[int, str, ...], Tuple[int, str]] = (42, "hello")

这个类型提示表示 args 变量可以是一个至少包含一个整数和一个字符串的元组,也可以是一个只包含整数和字符串的元组。这样可以表示一个更具体的元组类型,但不能直接表示包含任意数量和任意类型的元组。

那还真奇怪呀,都是...,只有和Any时才表示任意长度,其他情况下不是任意长度

你说得对,的确有点令人困惑。实际上,... 在类型提示中有不同的含义,取决于它所出现的上下文。

  1. Tuple[Any, ...]: 这里的 ... 表示任意数量的元素,而 Any 表示可以是任意类型。因此,Tuple[Any, ...] 表示一个可以包含任意数量和任意类型元素的元组。

  2. Union[Tuple[int, str, ...], Tuple[int, str]]: 这里的 ... 表示省略号,而不是表示任意数量的含义。在这个上下文中,... 并不是用来表示任意长度的元组,而是用来指示 Tuple 中的省略类型信息。这个类型提示表示变量可以是一个至少包含一个整数和一个字符串的元组,或者是一个只包含整数和字符串的元组。

        确实,... 的用法在类型提示中可能会有些让人困惑。在 Tuple 中,... 通常用于表示省略号,而在其他情况下,如 Tuple[Any, ...] 中,... 则表示任意数量的元素。这种差异可能并不直观,需要注意并理解上下文中的含义。希望这样的解释能够更清楚地说明这个问题。

四、类型提示只提供代码的可读性和静态类型检查的支持,并不会强制限制变量的实际类型

aa: List[str] = [1,2,3,34,4,5,"j"] 为什么不报错呀

        在Python中,类型提示只是对代码进行注释,不会在运行时进行类型检查。类型检查是由静态类型检查工具(如mypy)在开发阶段进行的。因此,即使你在类型提示中指定了 aa: List[str] 表示 aa 是一个字符串列表,但是在实际赋值时给 aa 赋了一个包含不同类型的元素的列表 [1,2,3,34,4,5,"j"],Python解释器不会报错。

        Python是一门动态类型语言,它允许你在运行时修改变量的类型。虽然类型提示可以提供代码的可读性和静态类型检查的支持,但并不会强制限制变量的实际类型。

第五章、Union联合类型

一、概述

类型提示支持Union(联合类型),用于指定多种可能的类型中的任意一个

        在 Python 的类型提示中,Union 类型用于指定多种可能的类型中的一个。它允许您指定一个变量、函数参数或返回值可以是多种类型中的任意一种。Union 类型使得代码更加灵活,允许处理多种不同的数据类型。

二、使用情况

1、类型提示为Union

2、容器类型中的元素类型为Union

使用 Union 类型可以帮助您更好地指定预期的数据类型,并增加代码的灵活性,使其能够处理多种不同类型的数据。

第六章、Any类型

一、概述

表示任意类型,是所有类型的父类,相当于object类型一样

        在 Python 的类型提示中,Any 类型用于表示任意类型。它表示变量可以是任何类型,或者函数可以接受任何类型的参数或返回任何类型的值。使用 Any 类型可以使代码更加灵活,允许处理不确定类型的数据。

二、使用情况

1、类型提示为Any

2、容器类型中的元素类型为Any

需要注意的是,使用 Any 类型可能会降低类型提示的精确性,并且可能隐藏潜在的类型错误。因此,应该尽量避免滥用 Any 类型,而是尽量使用更具体的类型来提高代码的可读性和可靠性。

第七章、类型提示前向引用

Python中类型提示侧重于型,必须类完整结束后,型才能确定

isinstance() 方法侧重于类,只要class 类名  执行后,则类已经声明了

一、概述

        前向引用(Forward reference)是指在代码中引用了一个尚未定义的类、函数、类型等标识符。通常在使用前向引用时,标识符的定义位于当前引用的位置之后。

        在 Python 中,前向引用通常用于类型提示(Type Hints)和字符串中。类型提示是一种在函数、方法、变量等声明中指定参数和返回值类型的方式。Python 3.7+ 支持类型提示的同时引入了前向引用的功能。

举个例子,假设有两个类 A 和 B,其中类 A 中使用了类 B 的引用。这时候可以在类 A 中使用字符串形式的前向引用来解决循环引用问题:

class A:
    def __init__(self, b: 'B'):
        self.b = b

class B:
    def __init__(self, a: A):
        self.a = a

# 这里的 'B' 是一个前向引用,指示了类 B 的存在,使得代码可以正确执行。

在这个例子中,类 A 的构造函数接受一个类型为 'B' 的参数 b,而类 B 的构造函数又接受一个类型为 A 的参数。由于类 A 和 B 的定义相互依赖,使用字符串形式的前向引用可以解决循环引用的问题。

前向引用使得 Python 在静态类型检查和类型提示时能够正确识别类的定义,而无需在前向引用的位置上实际定义类的内容。这使得代码更加简洁、易读,同时也避免了循环依赖的问题。

二、案例

class MyInt: def __init__(self, value): self.value = value def __add__(self, other:Any) -> MyInt: if isinstance(other, MyInt): return MyInt(self.value + other.value) else: raise 为什么这行代码, def __add__(self, other:Any) -> MyInt: 会识别不到MyInt尼

        在 Python 中,类型提示(Type Hints)是一种在函数或方法定义中指定参数类型和返回值类型的方法。类型提示可以提高代码的可读性和可维护性,同时也方便编辑器和开发工具进行静态代码分析和类型检查。

        在给方法 __add__ 加上类型提示时,需要确保引入 typing 模块中的 Any 类型。Any 类型表示任意类型,用于告诉编译器该参数可以是任意类型。由于 MyInt 类在这个文件中并未定义,所以 MyInt 类型不会被识别。

解决方法:

  1. 引入 MyInt 类的定义。
  2. 使用字符串形式表示类型:def __add__(self, other: "MyInt") -> "MyInt":,这样即使 MyInt 类没有被定义,编译器也不会报错。

下面是修正后的代码示例:

from typing import Any

class MyInt:
    def __init__(self, value):
        self.value = value

    def __add__(self, other: Any) -> 'MyInt':
        if isinstance(other, MyInt):
            return MyInt(self.value + other.value)
        else:
            raise TypeError("Unsupported operand type for +")

num1 = MyInt(5)
num2 = MyInt(10)
result = num1 + num2
print(result.value)  # 输出:15

        通过添加类型提示,即使 MyInt 类在 __add__ 方法的定义之前或之后,编译器仍然能够正确识别 MyInt 类型。

第八章、类型提示支持自定义类型

一、自定义类型相当于Python中的基本类型

自定义类型相当于int,float,bool,str等,只不过一般情况下是可变的

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

def distance(p1: Point, p2: Point) -> float:
    return ((p2.x - p1.x) ** 2 + (p2.y - p1.y)) ** 0.5

p1: Point = Point(1, 2)
p2: Point = Point(3, 7)
result: float = distance(p1, p2)
print(result) #3.0

在Python解释器中运行上述代码时,并不会进行类型检查。要进行类型检查,可以使用静态类型检查工具,如mypy

综上所述,类型提示是Python的一项强大功能,它可以提高代码的可读性和可维护性,帮助开发者更好地理解代码,并在静态类型检查工具中发现潜在的类型错误。

第九章、pyi文件

一、概述

        在Python中,.pyi文件是类型提示文件的一种。它是一个纯文本文件,用于为Python模块、函数、类和变量提供静态类型信息,以支持类型检查工具(如Mypy)在代码编写和维护过程中进行类型检查。

二、pyi文件的作用

   .pyi文件通常用于描述第三方库或Python标准库中的模块,特别是那些没有附带类型注释的模块。它们不包含实际的Python代码,而只包含类型提示信息,以帮助类型检查器了解函数和方法的输入参数类型、返回值类型以及变量的类型等信息。

        对于Python标准库和第三方库中的模块,.pyi文件通常是由库的维护者或社区贡献者编写的,并且可以与相应的源代码模块一起分发。类型提示文件为代码编辑器和类型检查工具提供了有关模块接口的信息,从而提供更好的代码自动完成、代码导航和类型检查功能。

        对于builtins.pyi文件,它通常用于描述Python的内置模块builtins,其中包含了Python的内置函数、异常和常量等的类型信息。这样,类型检查器就可以对这些内置函数的使用进行类型检查,从而提供更强大的类型检查功能。

        需要注意的是,.pyi文件并不是Python解释器在运行时加载的模块,它们只是为了类型检查而存在的静态类型提示文件。在实际运行Python代码时,.pyi文件不会被直接使用,而是作为辅助文件在开发阶段进行类型检查和代码提示。

三、pyi文件的用法

        在 Python 中,.pyi 文件是一种用于存储类型提示信息的文件。它们是与普通 Python 源文件相似的文本文件,但不包含实际的 Python 代码。相反,它们用于提供关于模块、类、函数和变量等的类型提示信息,以便提高代码的可读性和可靠性。

.pyi 文件通常用于提供第三方库或模块的类型提示信息,特别是对于那些无法直接修改源代码的库而言,这是一种常见的方式。它们允许开发者在不修改实际源代码的情况下为外部库添加类型提示。

例如,假设有一个名为 example.py 的 Python 源文件,它包含如下内容:

# example.py

def add(x: int, y: int) -> int:
    return x + y

可以为该源文件创建一个名为 example.pyi 的类型提示文件,其中包含有关该模块中函数的类型信息,如下所示:

# example.pyi

def add(x: int, y: int) -> int: ...

        在这个示例中,example.pyi 文件为 example.py 文件提供了类型提示信息,使得在其他代码中可以更准确地使用和调用 add 函数。

        使用 .pyi 文件可以提高代码的可读性和可靠性,并使得代码的类型检查更加准确。这对于大型项目和复杂的代码库来说尤为重要。

第十章、mypy类型检查器

一、概述

mypy 是一个流行的可选的静态类型检查器,用于在 Python 代码中发现类型错误。它允许开发者在编写 Python 代码时添加类型注释,并对代码进行静态类型检查,以帮助发现潜在的类型错误并提高代码的可靠性。

二、特点

以下是 mypy 类型检查器的一些特点和功能:

  1. 静态类型检查mypy 在不执行代码的情况下对代码进行静态类型检查,以查找潜在的类型错误并提供警告或错误信息。

  2. 支持类型注释mypy 支持使用类型注释来指定变量、函数参数和返回值的预期类型,以及其他复杂数据结构的类型。

  3. 可与 IDE 集成mypy 可以与许多常用的集成开发环境(IDE)集成,如 PyCharm、Visual Studio Code 等,以提供实时的类型检查和错误提示。

  4. 支持第三方库mypy 支持对许多常用的第三方库进行类型检查,并允许开发者为这些库添加自定义的类型提示信息。

  5. 可配置性高mypy 允许开发者通过配置文件来自定义类型检查的行为,包括指定忽略某些错误、自定义错误等级、调整类型检查的严格程度等。

通过使用 mypy 类型检查器,您可以提前发现潜在的类型错误,减少调试时间,并提高代码的可读性和可靠性。这使得 mypy 成为 Python 开发过程中一个有价值的工具。

三、安装及使用

使用 Mypy 进行 Python 静态类型检查_mypy attribute 'mro' of 'typeinfo' undefined_生信技术的博客-CSDN博客

python静态类型检查工具mypy_python mypy_zy010101的博客-CSDN博客

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值