Django:我什么时候需要 __eq__ 方法?

问题描述 投票:0回答:2

在 Django 中,我编写了一个自定义的基于类的验证器并实现了

__eq__
方法,因为它也是为 Django 本身已经实现的验证器完成的。

在这里你可以看到它:

@deconstructible
class FileSizeValidator:

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

    def __call__(self, value):
        limit = self.mb * 1024 * 1024
        if value.size > limit:
            raise ValidationError('File too big (max. ' + str(self.mb) + ' MiB).')

    def __eq__(self, other):
        return (
            isinstance(other, FileSizeValidator) and
            self.mb == other.mb
        )

现在,我还为

ImageField
编写了一个自定义类。我想将它用于
upload_to=
模型中的
ImageField
参数。在这里你可以看到我的例子:

@deconstructible
class RandomFileName:

    def __init__(self, directory=''):
        self.directory = directory

    def __call__(self, instance, filename):
        return self.directory + ("/" if self.directory else '') + get_random_string(7) + "." + filename.split('.')[-1]

    def __eq__(self, other):
        return (
            isinstance(other, RandomFileName) and
            self.directory == other.directory
        )

总的来说,我对它很满意,而且看起来效果很好。我只是不知道什么时候我需要

__eq__
方法,想请你解释一下。

python django
2个回答
2
投票

这称为运算符重载,在您的示例中,它用于比较两个对象。实现

__eq__()
方法后,您可以比较任何其他对象与您的对象是否相等。

我们现在可以从您的类中创建两个对象:

obj1 = FileSizeValidator(100)
obj2 = FileSizeValidator(200)

并且可以将它们比较为

obj1 == obj2

由于我们定义了自定义

__eq__()
,这将比较对象的
class
mb
属性的值,以返回
True
False
值。如果任何一个条件失败,都会返回
False

默认情况下,Python 中两个自定义对象的相等运算符会比较对象的

id
值,并且永远不会返回
True
,除非将对象与其自身进行比较。


0
投票

我认为这与您关心的问题不再相关。但是,你的问题很有趣,现有的答案还不够明确,所以我决定深入研究这个概念。结果如下:

你的问题:Django:我什么时候需要

__eq__
方法?

答案是:

Whenever you want to break the default rule of python to compare two custom objects by redefining your own rule, then you need this strategy.

记住,

__eq__
方法不仅仅与 Django Validator 相关 仅限班级。它相当适用于您创建的任何 python 类。

现在让我们深入了解细节。 假设你有一个名为

MyClass
的类,如下所示:

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

现在您初始化此类的三个不同对象:

object1 = MyClass(20)
object2 = MyClass(20)
object3 = MyClass(30)

现在如果我问你,

object1
object2
一样吗?你的答案是什么?是的,对吗?

是的,你是不正确。不相信我?然后转到您的终端并自行尝试。这些与 python 解释器不同,因为解释器通过对象的内存地址来比较类对象。由于

object1
object1
的内存地址不同,因此视为不相等。

但我们想打破这个规则。我们希望教育 python 解释器不根据对象的内存地址,而是根据我的指令来比较我的对象。让我们再次重新定义类。

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

    def __eq__(self, other):
        return isinstance(other, MyClass) and self.age == other.age

现在再次初始化该类的三个对象,

object1 = MyClass(20)
object2 = MyClass(20)
object3 = MyClass(30)

并在终端中比较对象1和对象2

object1 == object2:

这次又回来了

True
。因为,现在解释器不再遵循自己的规则来对自定义对象执行
==
比较运算符。相反,它在类的
__eq__
方法中发现,如果第二个对象的类与第一个对象的类相同,则比较结果将为
True
isinstance(other, MyClass)
and
第二个对象的年龄与第一个对象的年龄相同物体
self.age == other.age

那么,为什么我需要在自定义验证器类中包含

__eq__
方法?

这是因为,当您定义自定义验证类并执行

./manage.py makemigrations
时,django 的迁移框架会创建自定义验证类的对象,对于您的情况,它是
FileSizeValidator
类。当您下次执行
makemigrations
命令时,它会进行比较以检查您是否已更新验证要求(针对您的情况、文件大小)。如果系统发现现有对象和新对象不相等,则会为您更新的验证要求创建新的迁移对象。

那么,我的验证类中是否需要有这个方法?

一点也不。但是,这完全取决于您的要求。如果您认为,您永远不需要更新验证标准,所以不需要。但是如果您认为您可能需要更新它,例如,当前您允许用户上传最大大小为 5mb 的文件,并且迟早您可能需要将其更改为更少或更多,那么您必须重新定义

__eq__ 
方法。因为
__eq__
是向系统传达有关验证类标准更改的方式。

© www.soinside.com 2019 - 2024. All rights reserved.