Python中的魔术方法是什么,以及如何使用它们
Python的一个较少为人所知但非常有价值的功能是在对象上实现魔术方法。使用魔术方法,我们可以编写更干净、直观和易于理解的代码。
通过魔术方法,我们可以创建与对象交互的接口,使其更符合Python的特点。本文将介绍魔术方法,讨论创建魔术方法的最佳实践,并探讨您将遇到的常见魔术方法。
什么是魔术方法?
魔术方法是Python中定义对象在进行常见操作时的行为的方法。这些方法的名称前后都有两个下划线。
因此,它们通常被称为双下划线方法,即双下划线。您可能已经遇到过一个常见的双下划线方法,即用于定义类构造函数的 __init__()
方法。
通常情况下,不应直接在代码中调用双下划线方法;相反,它们将在程序运行时由解释器调用。
魔术方法有什么用?
魔术方法是面向对象编程中的一个有用概念。使用它们,您可以指定自定义数据类型在与常见内置操作一起使用时的行为。这些操作包括:
🟢 算术操作
🟢 比较操作
🟢 生命周期操作
🟢 表示操作
接下来的部分将讨论如何实现魔术方法,以定义应用在上述所有类别中使用时的行为。
如何定义魔术方法
如前所述,魔术方法指定了对象的行为。因此,它们作为对象类的一部分定义。因为它们是对象类的一部分,所以它们以作为第一个参数的self
开头,self
是对对象本身的引用。
它们可以接受其他参数,具体取决于它们将如何被解释器调用。它们还以两个下划线在名称之前和之后明确定义。
实现
到目前为止,我们讨论的大部分内容似乎都是理论和抽象的。在本节中,我们将实现一个简单的矩形类。
这个类将有长度和宽度属性。使用__init__方法,您可以在实例化时指定这些属性。此外,您将能够比较不同的矩形,看它们是否相等、小于或大于另一个矩形,使用==
、<
和>
运算符。最后,该矩形应能够提供有意义的字符串表示。
设置编码环境
为了跟随本教程,您需要一个Python运行环境。您可以使用本地环境,也可以使用online Geekflare Python compiler。
创建Rectangle类
首先,让我们开始定义Rectangle类。
class Rectangle:
pass
创建构造函数方法
接下来,让我们创建第一个魔术方法,即类构造函数方法。该方法将接受高度和宽度,并将它们存储为类实例的属性。
class Rectangle:
def __init__(self, height, width):
self.height = height
self.width = width
为字符串表示创建魔术方法
接下来,我们想要创建一个方法,使得我们的类能够生成一个可读性较好的字符串来表示对象。当我们调用str()
函数并传入Rectangle
类的一个实例作为参数时,将调用该方法。当你调用那些需要字符串参数的函数(比如print
函数)时,也会调用这个方法。
class Rectangle:
def __init__(self, height, width):
self.height = height
self.width = width
def __str__(self):
return f'Rectangle({self.height}, {self.width})'
__str__()
方法应该返回一个你想要表示该对象的字符串。在这个例子中,我们返回的字符串格式是Rectangle(, )
,其中和是矩形的存储尺寸。
为比较操作创建魔术方法
接下来,我们想要为等于、小于和大于操作创建比较运算符。这被称为运算符重载。为了创建这些方法,我们分别使用魔术方法__eq__
、__lt__
和__gt__
。这些方法将在比较矩形的面积之后返回一个布尔值。
class Rectangle:
def __init__(self, height, width):
self.height = height
self.width = width
def __str__(self):
return f'Rectangle({self.height}, {self.width})'
def __eq__(self, other):
""" 检查是否相等 """
return self.height * self.width == other.height * other.width
def __lt__(self, other):
""" 检查该矩形是否小于另一个矩形 """
return self.height * self.width other.height * other.width
如你所见,这些方法接收两个参数。第一个参数是当前矩形,第二个参数是它进行比较的其他值。这个值可以是另一个Rectangle实例或任何其他值。比较的逻辑和在哪些条件下比较将会返回true完全取决于你。
常见的魔术方法
在下一节中,我们将讨论你会遇到和使用的常见魔术方法。
#1. 算术运算
当你的类的一个实例位于算术符号的左侧时,算术魔术方法会被调用。该方法将以两个参数为参数调用,第一个是对该实例的引用,第二个值是符号右侧的对象。方法和符号如下:
名称 | 方法 | 符号 | 描述 |
加法 | __add__ |
+ | 实现加法 |
减法 | __sub__ |
– | 实现减法 |
乘法 | __mul__ |
* | 实现乘法 |
除法 | __div__ |
/ | 实现除法 |
整数除法 | __floordiv__ | // | 实现整数除法 |
#2. 比较操作
与算术魔术方法一样,这些方法在将定义它们的类的实例放置在比较运算符的左侧时被调用。与算术魔术方法一样,它们被调用时有两个参数;第一个是对对象实例的引用。第二个是对符号右侧的值的引用。
名称 | 方法 | 符号 | 描述 |
小于 | __lt__ |
< |
实现小于比较 |
大于 | __gt__ |
> |
实现大于比较 |
等于 | __eq__ |
== |
实现等于比较 |
小于等于 | __le__ |
>= |
实现小于等于比较 |
大于等于 | __ge__ |
<= |
实现大于等于比较 |
#3. 生命周期操作
这些方法将在对象的不同生命周期方法被调用时响应,例如实例化或删除。构造函数__init__
属于此类别。该类别中的常见方法列在下表中:
名称 | 方法 | 描述 |
构造函数 | __init__ |
每当删除所定义类的对象时调用此方法。它可以用于执行清理操作,如关闭它打开的任何文件。 |
删除 | __del__ |
每当删除所定义类的对象时调用此方法。它可以用于执行清理操作,如关闭它打开的任何文件。 |
新建 | __new__ | 当实例化指定类的对象时,首先调用__new__ 方法。该方法在构造函数之前调用,接受类以及任何额外的参数。它返回一个类的实例。在大多数情况下,它并不太有用,但在here中有详细介绍。 |
#4. 表示操作
名称 | 方法 | 描述 |
Str | __str__ | 返回对象的可读字符串表示。当调用str() 函数并传递类的实例作为参数时,将调用此方法。当将实例传递给print() 和format() 函数时也会调用它。它旨在提供一个用户可以理解的字符串。 |
Repr | __repr__ | 返回开发人员使用的对象的字符串表示。理想情况下,返回的字符串应该提供足够的信息,以便您可以仅凭字符串构建一个相同的对象。 |
创建魔术方法的最佳实践
魔术方法非常强大,可以简化您的代码。但是,在使用它们时要记住以下几点。
- 要适度使用它们——在类中实现过多的魔术方法会使你的代码难以理解。请限制自己只实现必要的方法。
- 在使用诸如`__setatrr__`和`__getattr__`等方法之前,请确保你理解它们的性能影响。
- 记录你的魔术方法的行为,这样其他开发人员就可以准确地了解它们的作用。这使得他们在使用时更容易,并在必要时进行调试。
最后的话
在本文中,我介绍了魔术方法作为一种使类能够与内置操作一起使用的方法。我还讨论了它们的定义,并通过一个实现了魔术方法的类的示例进行了说明。接下来,我提到了你可能会使用和需要的不同方法,并分享了一些需要记住的最佳实践。
接下来,你可能想要学习how to implement the Counter class in Python。