likes
comments
collection
share

[python]魔术方法大全(二)-- 比较篇

作者站长头像
站长
· 阅读数 13

引述

[python]魔术方法大全(二)-- 比较篇

print([1, 2] == [1, 2])
print(2 > 5)
print("a" <= "b")

输出结果为:

True
False
True

在python中我们经常会比较两个数据结构是否相等,或者比较两个数据结构的大小叫做rich comparison。

rich comparison一共包含了六个操作符。

[python]魔术方法大全(二)-- 比较篇

在python的内置数据结构中,比如说dict,或者list,尤其是integer、string、float,它们的rich comparison都是有良好的定义的。

然而,有时候对于我们自己写的数据结构,我们也希望利用这些比较运算符。

而比较的逻辑实现,我们就是通过魔术方法来完成的。

我们举个例子:

class Date:
    def __init__(self, year, month, date):
        self.year = year
        self.month = month
        self.date = date


x = Date(2022, 2, 22)
y = Date(2022, 2, 22)
print(x == y)

输出结果为:

False

在python中,当你没有去写一个类的比较逻辑的时候,它默认比较两个对象的是否相等的方法是会默认调用object.__eq__方法,默认比较两个对象的地址(id),默认调用了is

python中常见的比较魔术方法

__eq__魔术方法

__eq__ 是 Python 中一个重要的魔术方法,它用于判断两个对象是否相等。

__eq__ 方法默认情况下是比较两个对象的内存地址是否相等,即 id(self) == id(other)。如果我们想让自定义的类支持比较操作,就需要自定义 __eq__ 方法。

class Date:
    def __init__(self, year, month, date):
        self.year = year
        self.month = month
        self.date = date

    def __eq__(self, other):
        print("__eq__")
        return self.year == other.year and self.month == other.month and self.date == other.date


x = Date(2022, 2, 22)
y = Date(2022, 2, 22)
print(x == y)
print(x != y)

输出结果为:

__eq__
True
__eq__
False

这里我们并没有定义不等于,python默认调用了__eq__后取反。

__ne__魔术方法

__ne__是Python的一个魔术方法,用于比较两个对象是否不相等。它是“not equal”的缩写,与__eq__(等于)方法相对应。当使用!=操作符时,解释器就会调用__ne__方法来执行不相等的比较。

__ne__方法的默认实现是返回not self == other。因此,如果你在类中定义了__eq__方法,那么你应该同时定义__ne__方法,以确保比较的正确性。

class Date:
    def __init__(self, year, month, date):
        self.year = year
        self.month = month
        self.date = date

    def __eq__(self, other):
        print("__eq__")
        return self.year == other.year and self.month == other.month and self.date == other.date

    def __ne__(self, other):
        print("__ne__")
        return self.year != other.year and self.month != other.month and self.date != other.date


x = Date(2022, 2, 22)
y = Date(2022, 2, 22)
print(x == y)
print(x != y)

输出结果为:

__eq__
True
__ne__
False

这里不等于时就调用的__ne__

__gt__魔术方法

class Date:
    def __init__(self, year, month, date):
        self.year = year
        self.month = month
        self.date = date


x = Date(2022, 2, 22)
y = Date(2022, 2, 22)

print(x > y)

输出结果为:

Traceback (most recent call last):
  File "/mnt/f/lianhaifeng_codes/djangoProject/djangoProject/example2.py", line 20, in <module>
    print(x > y)
TypeError: '>' not supported between instances of 'Date' and 'Date'

__gt__是Python中的一个魔术方法,用于实现大于(greater than)比较运算符“>”。当我们使用“>”运算符来比较两个对象时,实际上是调用了其中一个对象的__gt__方法,这个方法返回True或False。

class Date:
    def __init__(self, year, month, date):
        self.year = year
        self.month = month
        self.date = date

    def __gt__(self, other):
        print("__gt__")
        if self.year > other.year:
            return True
        if self.month > other.month:
            return True
        if self.month == other.month:
            return self.date > other.date


x = Date(2022, 2, 22)
y = Date(2022, 2, 22)

print(x > y)
print(x < y)

输出结果为:

__gt__
False
__gt__
False

总之,__gt__是Python中的一个魔术方法,用于实现大于比较运算符“>”。通过定义__gt__方法,我们可以让我们的自定义对象支持“>”运算符。

尽管我们只实现了大于,但是也可以使用小于。

__lt__魔术方法

__lt__是Python中的一个魔术方法,用于重载小于号<的行为。该方法用于比较两个对象的大小关系,即是否小于。在Python中,如果两个对象无法比较大小,则会抛出TypeError异常。

class Date:
    def __init__(self, year, month, date):
        self.year = year
        self.month = month
        self.date = date

    def __gt__(self, other):
        print("__gt__")
        if self.year > other.year:
            return True
        if self.month > other.month:
            return True
        if self.month == other.month:
            return self.date > other.date

    def __lt__(self, other):
        print("__lt__")
        if self.year < other.year:
            return True
        if self.month < other.month:
            return True
        if self.month == other.month:
            return self.date < other.date


x = Date(2022, 2, 22)
y = Date(2022, 2, 22)

print(x > y)
print(x < y)

输出结果为:

__gt__
False
__lt__
False

在这里我们就会怀疑了了x<y语义上既是x小于y,又是y>x,到底是执行__gt__函数还是__lt__函数了?

举个栗子:

class Date:
    def __init__(self, year, month, date):
        self.year = year
        self.month = month
        self.date = date

    def __gt__(self, other):
        print("__gt__")
        if self.year > other.year:
            return True
        if self.month > other.month:
            return True
        if self.month == other.month:
            return self.date > other.date

    def __lt__(self, other):
        print("__lt__")
        if self.year < other.year:
            return True
        if self.month < other.month:
            return True
        if self.month == other.month:
            return self.date < other.date


class NewDate(Date):
    pass


x = Date(2022, 2, 22)
y = Date(2022, 2, 23)

print(x < y)

print(" ")
z = Date(2022, 2, 22)
zz = NewDate(2022, 2, 23)

print(z < zz)

输出结果为:

__lt__
True
 
__gt__
True

如果y是x的衍生类,优先使用y的rich comparison的函数,否者优先使用x的函数。大部分情况优先使用左边的函数。

__le____ge__魔术方法

__le__是Python中的一个特殊方法,用于实现对象之间小于等于比较运算符<=的行为。如果在类中定义了__le__方法,则当使用小于等于比较运算符时,Python将调用该方法来确定两个对象的大小关系。

__ge__是Python中的一个魔术方法,用于实现大于等于操作符(>=)的行为。该方法接收两个参数:selfother,其中self表示类的实例本身,other表示与之比较的另一个对象。该方法应该返回一个布尔值,表示两个对象的大小关系是否满足大于等于的条件。

class Date(object):
    def __init__(self, year, month, date):
        self.year = year
        self.month = month
        self.date = date

    def __ge__(self, other):
        print("__ge__")
        if self.year > other.year:
            return True
        if self.month > other.month:
            return True
        if self.month == other.month:
            return self.date > other.date

    def __le__(self, other):
        print("__le__")
        if self.year < other.year:
            return True
        if self.month < other.month:
            return True
        if self.month == other.month:
            return self.date < other.date


x = Date(2022, 2, 22)
y = Date(2022, 2, 23)

print(x <= y)

print(x >= y)

输出结果为:

__le__
True
__ge__
False

__hash__魔术方法

在 Python 中,__hash__() 函数是一个魔术方法,用于返回对象的哈希值。哈希值是一个整数,用于在字典查找中快速比较两个对象是否相等。在使用字典、集合等可哈希类型时,需要实现这个方法。

__hash__() 函数应该返回一个整数。如果两个对象相等,则它们的哈希值必须相同,反之则不一定成立。

实现 __hash__() 函数通常要和 __eq__() 函数配合使用,保证对象的哈希值与相等性有关。例如,如果两个对象相等,则它们的哈希值也相等,可以实现如下:

class MyClass:
    def __init__(self, x):
        self.x = x

    def __eq__(self, other):
        if not isinstance(other, MyClass):
            return NotImplemented
        return self.x == other.x

    def __hash__(self):
        return hash(self.x)

在这个例子中,我们定义了一个自定义类 MyClass,它包含一个属性 x。我们实现了 __eq__() 方法,以便在比较对象时使用,如果两个对象的 x 属性相等,则它们相等。我们还实现了 __hash__() 方法,它返回对象的哈希值,这里使用 hash() 内置函数对对象的 x 属性进行哈希。

当我们使用这个类创建对象时,我们可以将它们添加到字典中,并使用 __eq__() 方法进行比较,例如:

a = MyClass(1)
b = MyClass(1)
c = MyClass(2)

print(a == b)  # True
print(a == c)  # False

d = {a: 'value'}
print(d[b])  # 'value'

在上面的例子中,我们创建了三个对象 abc,其中 abx 属性相等,而 cx 属性不同。我们可以使用 == 运算符比较它们的相等性,也可以将它们添加到字典 d 中,使用哈希值进行比较,最终输出 'value'

总之,__hash__() 函数在 Python 中是非常重要的,它为我们提供了一种快速比较对象是否相等的方法,使我们能够在使用字典、集合等可哈希类型时,快速查找对象。

__bool__魔术方法

__bool__是Python中的一个魔术方法,也称为特殊方法或者魔法方法,它是在类中实现用于定义实例转换为布尔值的方式。当Python需要将实例转换为布尔值(例如,在条件语句中使用)时,会调用该方法。

__bool__方法应该返回一个布尔值True或False,来表示对象是否被视为“真”或“假”。如果该方法没有被定义,则默认返回True,因为Python中的所有对象都被视为“真”,除非它们明确地定义为“假”。

下面是一个简单的例子,展示了如何在类中定义__bool__方法:

class MyClass:
    def __init__(self, num):
        self.num = num

    def __bool__(self):
        return self.num > 0

在上面的例子中,MyClass类的__bool__方法返回self.num > 0的结果,这表示当num大于0时,该实例被视为“真”,否则被视为“假”。在实际使用中,可以像下面这样使用这个类:

>>> x = MyClass(5)
>>> if x:
...     print("x is true")
...
x is true
>>> y = MyClass(0)
>>> if not y:
...     print("y is false")
...
y is false

在上面的例子中,我们创建了两个MyClass实例,一个具有正数的num属性,另一个具有零值的num属性。我们使用条件语句检查这些实例,以确定它们是否被视为“真”或“假”。