创建新的原始类型

Beginner

This tutorial is from open-source community. Access the source code

简介

在这个实验中,你将学习如何在 Python 中创建一个新的原始类型,并为其实现必要的方法。你还将了解 Python 的对象协议。在大多数 Python 程序中,像 intfloatstr 这样的内置原始类型被用来表示数据。不过,Python 允许你创建自定义类型,标准库中的 decimalfractions 等模块就是例子。

在这个实验中,你将创建一个名为 MutInt(可变整数)的新原始类型。与 Python 的不可变整数不同,MutInt 在创建后可以被修改。这个练习将展示在 Python 中创建一个功能完备的原始类型所需的基本原则。

这是一个实验(Guided Lab),提供逐步指导来帮助你学习和实践。请仔细按照说明完成每个步骤,获得实际操作经验。根据历史数据,这是一个 初级 级别的实验,完成率为 90%。获得了学习者 97% 的好评率。

创建基本的 MutInt 类

让我们从为可变整数类型创建一个基本类开始。在编程中,类就像是创建对象的蓝图。在这一步,我们将为新的原始类型奠定基础。原始类型是编程语言提供的基本数据类型,在这里我们要创建自己的自定义类型。

  1. 打开 WebIDE 并导航到 /home/labex/project 目录。WebIDE 是一个集成开发环境,你可以在其中编写、编辑和运行代码。导航到这个目录可确保你所有的文件都组织在一处,并且能相互正确交互。

  2. 打开在设置步骤中为你创建的 mutint.py 文件。这个文件将是我们 MutInt 类定义的所在之处。

  3. 添加以下代码来定义一个基本的 MutInt 类:

## mutint.py

class MutInt:
    """
    A mutable integer class that allows its value to be modified after creation.
    """
    __slots__ = ['value']

    def __init__(self, value):
        """Initialize with an integer value."""
        self.value = value

__slots__ 属性用于定义这个类可以拥有的属性。属性就像是属于类对象的变量。通过使用 __slots__,我们告诉 Python 使用更节省内存的方式来存储属性。在这种情况下,我们的 MutInt 类将只有一个名为 value 的属性。这意味着 MutInt 类的每个对象只能保存一个数据,即整数值。

__init__ 方法是我们类的构造函数。构造函数是一种特殊的方法,在创建类的对象时会被调用。它接受一个值参数,并将其存储在实例的 value 属性中。实例是根据类蓝图创建的单个对象。

让我们通过创建一个 Python 脚本来使用这个类来测试它:

  1. 在同一目录下创建一个名为 test_mutint.py 的新文件:
## test_mutint.py

from mutint import MutInt

## Create a MutInt object
a = MutInt(3)
print(f"Created MutInt with value: {a.value}")

## Modify the value (demonstrating mutability)
a.value = 42
print(f"Modified value to: {a.value}")

## Try adding (this will fail)
try:
    result = a + 10
    print(f"Result of a + 10: {result}")
except TypeError as e:
    print(f"Error when adding: {e}")

在这个测试脚本中,我们首先从 mutint.py 文件中导入 MutInt 类。然后我们创建一个初始值为 3 的 MutInt 类对象。我们打印初始值,然后将其修改为 42 并打印新值。最后,我们尝试将 10 加到 MutInt 对象上,这会导致错误,因为我们的类还不支持加法运算。

  1. 在终端中执行以下命令来运行测试脚本:
python3 /home/labex/project/test_mutint.py

终端是一个命令行界面,你可以在其中运行各种命令来与系统和代码进行交互。运行这个命令将执行 test_mutint.py 脚本。

你应该会看到类似以下的输出:

Created MutInt with value: 3
Modified value to: 42
Error when adding: unsupported operand type(s) for +: 'MutInt' and 'int'

我们的 MutInt 类成功地存储和更新了一个值。然而,它有几个局限性:

  • 打印时显示效果不佳
  • 不支持加法等数学运算
  • 不支持比较操作
  • 不支持类型转换

在接下来的步骤中,我们将逐一解决这些局限性,使我们的 MutInt 类更像一个真正的原始类型。

改进字符串表示形式

当你在 Python 中打印一个 MutInt 对象时,你会看到类似 <__main__.MutInt object at 0x...> 这样的输出。这个输出没什么用,因为它没有告诉你 MutInt 对象的实际值。为了让你更容易理解这个对象代表什么,我们将为字符串表示形式实现特殊方法。

  1. 在 WebIDE 中打开 mutint.py 文件,并使用以下代码更新它:
## mutint.py

class MutInt:
    """
    A mutable integer class that allows its value to be modified after creation.
    """
    __slots__ = ['value']

    def __init__(self, value):
        """Initialize with an integer value."""
        self.value = value

    def __str__(self):
        """Return a string representation for printing."""
        return str(self.value)

    def __repr__(self):
        """Return a developer-friendly string representation."""
        return f'MutInt({self.value!r})'

    def __format__(self, fmt):
        """Support string formatting with format specifications."""
        return format(self.value, fmt)

我们为 MutInt 类添加了三个重要的方法:

  • __str__():当你对对象使用 str() 函数或直接打印对象时,会调用这个方法。它应该返回一个人类可读的字符串。
  • __repr__():这个方法提供对象的“官方”字符串表示形式。它主要用于调试,理想情况下应该返回一个字符串,如果将这个字符串传递给 eval() 函数,应该能重新创建该对象。
  • __format__():这个方法允许你对 MutInt 对象使用 Python 的字符串格式化系统。你可以使用诸如填充和数字格式化之类的格式说明符。
  1. 创建一个名为 test_string_repr.py 的新测试文件,来测试这些新方法:
## test_string_repr.py

from mutint import MutInt

## Create a MutInt object
a = MutInt(3)

## Test string representation
print(f"str(a): {str(a)}")
print(f"repr(a): {repr(a)}")

## Test direct printing
print(f"Print a: {a}")

## Test string formatting
print(f"Formatted with padding: '{a:*^10}'")
print(f"Formatted as decimal: '{a:d}'")

## Test mutability
a.value = 42
print(f"After changing value, repr(a): {repr(a)}")

在这个测试文件中,我们首先导入 MutInt 类。然后创建一个值为 3MutInt 对象。我们通过使用 str()repr() 函数来测试 __str__()__repr__() 方法。我们还测试了直接打印、字符串格式化以及 MutInt 对象的可变性。

  1. 运行测试脚本:
python3 /home/labex/project/test_string_repr.py

当你运行这个命令时,Python 将执行 test_string_repr.py 脚本。你应该会看到类似以下的输出:

str(a): 3
repr(a): MutInt(3)
Print a: 3
Formatted with padding: '****3*****'
Formatted as decimal: '3'
After changing value, repr(a): MutInt(42)

现在我们的 MutInt 对象显示效果很好。字符串表示形式展示了其底层的值,并且我们可以像处理普通整数一样使用字符串格式化。

__str__()__repr__() 的区别在于,__str__() 旨在产生一个对人类友好的输出,而 __repr__() 理想情况下应该产生一个字符串,当将其传递给 eval() 函数时,能够重新创建该对象。这就是为什么我们在 __repr__() 方法中包含了类名。

__format__() 方法使我们的对象能够与 Python 的格式化系统配合使用,因此我们可以使用诸如填充和数字格式化之类的格式说明符。

添加数学运算

目前,我们的 MutInt 类不支持加法等数学运算。在 Python 中,要为自定义类启用此类运算,我们需要实现特殊方法。这些特殊方法也被称为“魔术方法”或“双下划线方法”,因为它们被双下划线包围。让我们通过实现算术运算的相关特殊方法来添加加法功能。

  1. 在 WebIDE 中打开 mutint.py 文件,并使用以下代码更新它:
## mutint.py

class MutInt:
    """
    A mutable integer class that allows its value to be modified after creation.
    """
    __slots__ = ['value']

    def __init__(self, value):
        """Initialize with an integer value."""
        self.value = value

    def __str__(self):
        """Return a string representation for printing."""
        return str(self.value)

    def __repr__(self):
        """Return a developer-friendly string representation."""
        return f'MutInt({self.value!r})'

    def __format__(self, fmt):
        """Support string formatting with format specifications."""
        return format(self.value, fmt)

    def __add__(self, other):
        """Handle addition: self + other."""
        if isinstance(other, MutInt):
            return MutInt(self.value + other.value)
        elif isinstance(other, int):
            return MutInt(self.value + other)
        else:
            return NotImplemented

    def __radd__(self, other):
        """Handle reversed addition: other + self."""
        ## For commutative operations like +, we can reuse __add__
        return self.__add__(other)

    def __iadd__(self, other):
        """Handle in-place addition: self += other."""
        if isinstance(other, MutInt):
            self.value += other.value
            return self
        elif isinstance(other, int):
            self.value += other
            return self
        else:
            return NotImplemented

我们为 MutInt 类添加了三个新方法:

  • __add__():当 + 运算符用于 MutInt 对象在左侧时,会调用此方法。在该方法内部,我们首先检查 other 操作数是 MutInt 实例还是 int 类型。如果是,则执行加法并返回一个包含结果的新 MutInt 对象。如果 other 操作数是其他类型,我们返回 NotImplemented。这会告诉 Python 尝试其他方法或抛出 TypeError
  • __radd__():当 + 运算符用于 MutInt 对象在右侧时,会调用此方法。由于加法是可交换运算(即 a + bb + a 相同),我们可以直接复用 __add__ 方法。
  • __iadd__():当 += 运算符用于 MutInt 对象时,会调用此方法。它不会创建新对象,而是修改现有的 MutInt 对象并返回它。
  1. 创建一个名为 test_math_ops.py 的新测试文件,来测试这些新方法:
## test_math_ops.py

from mutint import MutInt

## Create MutInt objects
a = MutInt(3)
b = MutInt(5)

## Test regular addition
c = a + b
print(f"a + b = {c}")

## Test addition with int
d = a + 10
print(f"a + 10 = {d}")

## Test reversed addition
e = 7 + a
print(f"7 + a = {e}")

## Test in-place addition
print(f"Before a += 5: a = {a}")
a += 5
print(f"After a += 5: a = {a}")

## Test in-place addition with reference sharing
f = a  ## f and a point to the same object
print(f"Before a += 10: a = {a}, f = {f}")
a += 10
print(f"After a += 10: a = {a}, f = {f}")

## Test unsupported operation
try:
    result = a + 3.5  ## Adding a float is not supported
    print(f"a + 3.5 = {result}")
except TypeError as e:
    print(f"Error when adding float: {e}")

在这个测试文件中,我们首先导入 MutInt 类。然后创建一些 MutInt 对象并执行不同类型的加法运算。我们还测试了原地加法以及尝试不支持的运算(添加浮点数)的情况。

  1. 运行测试脚本:
python3 /home/labex/project/test_math_ops.py

你应该会看到类似以下的输出:

a + b = MutInt(8)
a + 10 = MutInt(13)
7 + a = MutInt(10)
Before a += 5: a = MutInt(3)
After a += 5: a = MutInt(8)
Before a += 10: a = MutInt(8), f = MutInt(8)
After a += 10: a = MutInt(18), f = MutInt(18)
Error when adding float: unsupported operand type(s) for +: 'MutInt' and 'float'

现在我们的 MutInt 类支持基本的加法运算。注意,当我们使用 += 时,af 都被更新了。这表明 a += 10 修改了现有对象,而不是创建了一个新对象。

这种可变对象的行为类似于 Python 的内置可变类型,如列表。例如:

a = [1, 2, 3]
b = a
a += [4, 5]  ## Both a and b are updated

相比之下,对于元组等不可变类型,+= 会创建一个新对象:

c = (1, 2, 3)
d = c
c += (4, 5)  ## c is a new object, d still points to the old one

实现比较运算

目前,我们的 MutInt 对象无法相互比较,也不能与普通整数进行比较。在 Python 中,像 ==<<=>>= 这样的比较运算在处理对象时非常有用。它们能让我们确定不同对象之间的关系,这在许多编程场景中(如排序、过滤和条件语句)至关重要。所以,让我们通过实现比较运算的特殊方法,为 MutInt 类添加比较功能。

  1. 在 WebIDE 中打开 mutint.py 文件,并使用以下代码更新它:
## mutint.py

from functools import total_ordering

@total_ordering
class MutInt:
    """
    A mutable integer class that allows its value to be modified after creation.
    """
    __slots__ = ['value']

    def __init__(self, value):
        """Initialize with an integer value."""
        self.value = value

    def __str__(self):
        """Return a string representation for printing."""
        return str(self.value)

    def __repr__(self):
        """Return a developer-friendly string representation."""
        return f'MutInt({self.value!r})'

    def __format__(self, fmt):
        """Support string formatting with format specifications."""
        return format(self.value, fmt)

    def __add__(self, other):
        """Handle addition: self + other."""
        if isinstance(other, MutInt):
            return MutInt(self.value + other.value)
        elif isinstance(other, int):
            return MutInt(self.value + other)
        else:
            return NotImplemented

    def __radd__(self, other):
        """Handle reversed addition: other + self."""
        return self.__add__(other)

    def __iadd__(self, other):
        """Handle in-place addition: self += other."""
        if isinstance(other, MutInt):
            self.value += other.value
            return self
        elif isinstance(other, int):
            self.value += other
            return self
        else:
            return NotImplemented

    def __eq__(self, other):
        """Handle equality comparison: self == other."""
        if isinstance(other, MutInt):
            return self.value == other.value
        elif isinstance(other, int):
            return self.value == other
        else:
            return NotImplemented

    def __lt__(self, other):
        """Handle less-than comparison: self < other."""
        if isinstance(other, MutInt):
            return self.value < other.value
        elif isinstance(other, int):
            return self.value < other
        else:
            return NotImplemented

我们做了几个关键改进:

  1. functools 模块导入并使用 @total_ordering 装饰器。@total_ordering 装饰器是 Python 中的一个强大工具。在为类实现比较方法时,它能帮我们节省大量时间和精力。我们无需手动定义全部六个比较方法(__eq____ne____lt____le____gt____ge__),只需定义 __eq__ 和另一个比较方法(在我们的例子中是 __lt__)。装饰器会自动为我们生成其余四个比较方法。

  2. 添加 __eq__() 方法来处理相等比较(==)。此方法用于检查两个 MutInt 对象,或者一个 MutInt 对象和一个整数是否具有相同的值。

  3. 添加 __lt__() 方法来处理小于比较(<)。此方法用于确定一个 MutInt 对象,或者一个 MutInt 对象与一个整数相比,其值是否更小。

  4. 创建一个名为 test_comparisons.py 的新测试文件,来测试这些新方法:

## test_comparisons.py

from mutint import MutInt

## Create MutInt objects
a = MutInt(3)
b = MutInt(3)
c = MutInt(5)

## Test equality
print(f"a == b: {a == b}")  ## Should be True (same value)
print(f"a == c: {a == c}")  ## Should be False (different values)
print(f"a == 3: {a == 3}")  ## Should be True (comparing with int)
print(f"a == 5: {a == 5}")  ## Should be False (different values)

## Test less than
print(f"a < c: {a < c}")    ## Should be True (3 < 5)
print(f"c < a: {c < a}")    ## Should be False (5 is not < 3)
print(f"a < 4: {a < 4}")    ## Should be True (3 < 4)

## Test other comparisons (provided by @total_ordering)
print(f"a <= b: {a <= b}")  ## Should be True (3 <= 3)
print(f"a > c: {a > c}")    ## Should be False (3 is not > 5)
print(f"c >= a: {c >= a}")  ## Should be True (5 >= 3)

## Test with a different type
print(f"a == '3': {a == '3'}")  ## Should be False (different types)

在这个测试文件中,我们创建了几个 MutInt 对象,并对它们进行不同的比较运算。我们还将 MutInt 对象与普通整数以及不同类型(这里是字符串)进行比较。通过运行这些测试,我们可以验证比较方法是否按预期工作。

  1. 运行测试脚本:
python3 /home/labex/project/test_comparisons.py

你应该会看到类似以下的输出:

a == b: True
a == c: False
a == 3: True
a == 5: False
a < c: True
c < a: False
a < 4: True
a <= b: True
a > c: False
c >= a: True
a == '3': False

现在我们的 MutInt 类支持所有比较运算。

@total_ordering 装饰器特别有用,因为它让我们无需手动实现全部六个比较方法。只需提供 __eq____lt__,Python 就能自动推导出其他四个比较方法。

在实现自定义类时,通常的最佳实践是让它们既能与同类对象协作,也能在合理的情况下与内置类型协作。这就是为什么我们的比较方法既能处理 MutInt 对象,也能处理普通整数。这样,我们的 MutInt 类就能在不同的编程场景中更灵活地使用。

添加类型转换

我们的 MutInt 类目前支持加法和比较运算。但是,它不能与 Python 的内置转换函数(例如 int()float())一起使用。这些转换函数在 Python 中非常有用。例如,当你想要将一个值转换为整数或浮点数以进行不同的计算或操作时,你需要依赖这些函数。因此,让我们为 MutInt 类添加与它们一起使用的功能。

  1. 在 WebIDE 中打开 mutint.py,并使用以下代码更新它:
## mutint.py

from functools import total_ordering

@total_ordering
class MutInt:
    """
    A mutable integer class that allows its value to be modified after creation.
    """
    __slots__ = ['value']

    def __init__(self, value):
        """Initialize with an integer value."""
        self.value = value

    def __str__(self):
        """Return a string representation for printing."""
        return str(self.value)

    def __repr__(self):
        """Return a developer - friendly string representation."""
        return f'MutInt({self.value!r})'

    def __format__(self, fmt):
        """Support string formatting with format specifications."""
        return format(self.value, fmt)

    def __add__(self, other):
        """Handle addition: self + other."""
        if isinstance(other, MutInt):
            return MutInt(self.value + other.value)
        elif isinstance(other, int):
            return MutInt(self.value + other)
        else:
            return NotImplemented

    def __radd__(self, other):
        """Handle reversed addition: other + self."""
        return self.__add__(other)

    def __iadd__(self, other):
        """Handle in - place addition: self += other."""
        if isinstance(other, MutInt):
            self.value += other.value
            return self
        elif isinstance(other, int):
            self.value += other
            return self
        else:
            return NotImplemented

    def __eq__(self, other):
        """Handle equality comparison: self == other."""
        if isinstance(other, MutInt):
            return self.value == other.value
        elif isinstance(other, int):
            return self.value == other
        else:
            return NotImplemented

    def __lt__(self, other):
        """Handle less - than comparison: self < other."""
        if isinstance(other, MutInt):
            return self.value < other.value
        elif isinstance(other, int):
            return self.value < other
        else:
            return NotImplemented

    def __int__(self):
        """Convert to int."""
        return self.value

    def __float__(self):
        """Convert to float."""
        return float(self.value)

    __index__ = __int__  ## Support array indexing and other operations requiring an index

    def __lshift__(self, other):
        """Handle left shift: self << other."""
        if isinstance(other, MutInt):
            return MutInt(self.value << other.value)
        elif isinstance(other, int):
            return MutInt(self.value << other)
        else:
            return NotImplemented

    def __rlshift__(self, other):
        """Handle reversed left shift: other << self."""
        if isinstance(other, int):
            return MutInt(other << self.value)
        else:
            return NotImplemented

我们向 MutInt 类添加了三个新方法:

  1. __int__(): 当你在我们的 MutInt 类的对象上使用 int() 函数时,会调用此方法。例如,如果你有一个 MutInt 对象 a,并且你编写了 int(a),Python 将调用 a 对象的 __int__() 方法。
  2. __float__(): 类似地,当你在我们的 MutInt 对象上使用 float() 函数时,会调用此方法。
  3. __index__(): 此方法用于专门需要整数索引的操作。例如,当你想要使用索引访问列表中的元素,或执行位长度操作时,Python 需要一个整数索引。
  4. __lshift__(): 当 MutInt 对象位于 << 运算符的左侧时,此方法处理左移操作。
  5. __rlshift__(): 当 MutInt 对象位于 << 运算符的右侧时,此方法处理左移操作。

__index__ 方法对于需要整数索引的操作至关重要,例如列表索引、切片和位长度操作。在我们的简单实现中,我们将其设置为与 __int__ 相同,因为我们的 MutInt 对象的值可以直接用作整数索引。

__lshift____rlshift__ 方法对于支持按位左移操作至关重要。它们允许我们的 MutInt 对象参与按位运算,这是类整数类型(integer-like types)的常见要求。

  1. 创建一个名为 test_conversions.py 的新测试文件来测试这些新方法:
## test_conversions.py

from mutint import MutInt

## Create a MutInt object
a = MutInt(3)

## Test conversions
print(f"int(a): {int(a)}")
print(f"float(a): {float(a)}")

## Test using as an index
names = ['Dave', 'Guido', 'Paula', 'Thomas', 'Lewis']
print(f"names[a]: {names[a]}")

## Test using in bit operations (requires __index__)
print(f"1 << a: {1 << a}")  ## Shift left by 3

## Test hex/oct/bin functions (requires __index__)
print(f"hex(a): {hex(a)}")
print(f"oct(a): {oct(a)}")
print(f"bin(a): {bin(a)}")

## Modify and test again
a.value = 4
print(f"\nAfter changing value to 4:")
print(f"int(a): {int(a)}")
print(f"names[a]: {names[a]}")
  1. 运行测试脚本:
python3 /home/labex/project/test_conversions.py

你应该看到类似于这样的输出:

int(a): 3
float(a): 3.0
names[a]: Thomas
1 << a: 8
hex(a): 0x3
oct(a): 0o3
bin(a): 0b11

After changing value to 4:
int(a): 4
names[a]: Lewis

现在,我们的 MutInt 类可以转换为标准 Python 类型,并用于需要整数索引的操作。

__index__ 方法尤为重要。它是在 Python 中引入的,允许对象在需要整数索引的情况下使用,例如列表索引、按位运算和各种函数(如 hex()oct()bin())。

通过这些添加,我们的 MutInt 类现在是一个相当完整的原始类型(primitive type)。它可以在大多数可以使用常规整数的上下文中使用,并且具有可变的额外好处。

完整的 MutInt 实现

这是我们完整的 MutInt 实现,包含我们添加的所有功能:

## mutint.py

from functools import total_ordering

@total_ordering
class MutInt:
    """
    A mutable integer class that allows its value to be modified after creation.
    """
    __slots__ = ['value']

    def __init__(self, value):
        """Initialize with an integer value."""
        self.value = value

    def __str__(self):
        """Return a string representation for printing."""
        return str(self.value)

    def __repr__(self):
        """Return a developer - friendly string representation."""
        return f'MutInt({self.value!r})'

    def __format__(self, fmt):
        """Support string formatting with format specifications."""
        return format(self.value, fmt)

    def __add__(self, other):
        """Handle addition: self + other."""
        if isinstance(other, MutInt):
            return MutInt(self.value + other.value)
        elif isinstance(other, int):
            return MutInt(self.value + other)
        else:
            return NotImplemented

    def __radd__(self, other):
        """Handle reversed addition: other + self."""
        return self.__add__(other)

    def __iadd__(self, other):
        """Handle in - place addition: self += other."""
        if isinstance(other, MutInt):
            self.value += other.value
            return self
        elif isinstance(other, int):
            self.value += other
            return self
        else:
            return NotImplemented

    def __eq__(self, other):
        """Handle equality comparison: self == other."""
        if isinstance(other, MutInt):
            return self.value == other.value
        elif isinstance(other, int):
            return self.value == other
        else:
            return NotImplemented

    def __lt__(self, other):
        """Handle less - than comparison: self < other."""
        if isinstance(other, MutInt):
            return self.value < other.value
        elif isinstance(other, int):
            return self.value < other
        else:
            return NotImplemented

    def __int__(self):
        """Convert to int."""
        return self.value

    def __float__(self):
        """Convert to float."""
        return float(self.value)

    __index__ = __int__  ## Support array indexing and other operations requiring an index

    def __lshift__(self, other):
        """Handle left shift: self << other."""
        if isinstance(other, MutInt):
            return MutInt(self.value << other.value)
        elif isinstance(other, int):
            return MutInt(self.value << other)
        else:
            return NotImplemented

    def __rlshift__(self, other):
        """Handle reversed left shift: other << self."""
        if isinstance(other, int):
            return MutInt(other << self.value)
        else:
            return NotImplemented

此实现涵盖了在 Python 中创建新原始类型(primitive type)的关键方面。为了使其更加完整,你可以为其他操作(如减法、乘法、除法等)实现其他方法。

总结

在这个实验中,你学习了如何在 Python 中创建自己的原始类型。具体来说,你掌握了创建一个类似于内置类型的可变整数类,实现用于对象显示的特殊方法,添加对数学和比较运算的支持,以及为各种 Python 上下文启用类型转换。

这些概念对于理解 Python 的对象模型至关重要,并且可用于创建能与内置操作良好集成的自定义类型。为了进一步提升你的知识水平,你可以考虑实现更多的数学运算,添加对其他内置函数的支持,以及探索像自定义集合这样的复杂类型。Python 中的自定义类型是根据特定需求扩展该语言的强大工具。