PyCharm可以自动生成__eq__()和__hash__()实现吗?

26
我是PyCharm的新手,但长期使用IntelliJ。在IntelliJ中,当您编写类定义时,IDE可以根据实例变量自动生成构造函数、equals()方法和hashCode()方法。这不仅有助于节省输入时间,还可以防止意外错误,并自动引入一些equals()和hashCode()最佳实践。我希望PyCharm也能做到这一点,考虑到这两个产品来自同一家公司。经过大量搜索和查找文档,我没有找到任何关于__eq__()或__hash__()的信息。尽管Python实例变量没有明确指定,但我希望生成器可以遵循一种约定,例如提供所有__init__()参数作为潜在的实例变量。至于__init__(),我发现了一些自动添加实例变量设置的方法到__init__()中,但这种方法似乎比直接输入更麻烦,而且它甚至没有将实例变量添加为__init__()签名的参数。

我在文档中是否忽略了什么,或者可能有插件可以做到这一点?

更新:明确一下,我正在寻找能够生成这些方法实际实现的工具。也就是说,如果我有一个名为Point的类,并且PyCharm知道我的类有xy实例变量,那么它将自动为__eq__()方法生成以下内容:

def __eq__(self, other):
    if not isinstance(other, Point):
        return NotImplemented
    elif self is other:
        return True
    else:
        return self.x == other.x and self.y == other.y

在IntelliJ中很容易实现等效功能。

3个回答

12

你可以创建一个Live Template

在文件->设置->编辑器->Live Templates下寻找Python,点击+添加,然后命名为"class"并确保在Python文件的GUI中添加上下文。

模板文本:

class $class_name$:
    """$class_docstring$"""

    def __init__(self, $args$):
        """$init_docstring$"""
        pass

    def __eq__(self, $other$):
        if not isinstance($other$, $class_name$):
            return NotImplemented
        elif self is $other$:
            return True
        else:
            return self.$eq_field$ == $other$.$eq_field$

    def __hash__(self, ):
        pass
    $END$

我将我的"选项" -> "展开方式"部分设置为"默认(选项卡)"。 从此时开始,当您键入"class"时,可以使用Tab自动完成来插入实时模板。如果在Live Template Text中作为变量包含了任何部分,则光标将被弹回到该部分。

更复杂的,例如列表类型,LiveTemplate不支持变量。例如,实时模板文本中的条件语句或列表扩展似乎不可用。


我缩进了类体并在每个语句中添加了 def,它成功运行了。但是它没有生成这些方法的实际主体 - 除非我使用它的方式不正确? - sparc_spread
谢谢,我已经更新了我的答案以修复语法错误,真是尴尬。在上面的示例中,我只在这些方法的主体中放置了关键字pass,你可以写任何你喜欢的东西,并将其放在那个位置,但是,使这些主体通用是一个棘手的问题,我认为。例如,您可以给出一个通用的__hash__()的示例吗? - OYRM
1
没问题。对于__eq __(),我正在寻找类似于我在我的OP中添加的示例的内容。对于__hash __()此问题中显示的实现看起来不错-在与__eq __()中比较的相同事物的元组上调用hash()。问题是我不认为PyCharm live模板语言本身足够丰富,可以根据变量输入迭代生成代码块。我找了又找,但我仍然可能弄错了。 - sparc_spread
@sparc_spread,我已经尽可能地扩展了__eq__()方法,以展示在LiveTemplate系统中更深入的使用,但我认为你对迭代生成的看法是正确的。因此,在上面_eq的例子中,我只创建了一个eq_field,而不是与self.a和self.b进行比较,原因是在LiveTemplate帮助系统中声明的变量类型似乎没有显示任何可以解决这个问题的文档。 - OYRM
我同意,我认为这是我们能做到的最好程度了。很遗憾,在IntelliJ中不使用实时模板,通过“Code...->Generate”菜单功能真的很容易完成。无论如何,除非PyCharm 4.5出现了新的东西,否则我相信你的答案是正确的。至少我们已经自动生成了__eq __()部分,遵循了最佳实践,如果比较的类不同,则返回NotImplemented - sparc_spread

3
也许数据类(data classes)的概念对您也很有趣呢?以下是来自文档中的示例:
https://docs.python.org/3/library/dataclasses.html
from dataclasses import dataclass

@dataclass
class InventoryItem:
    """Class for keeping track of an item in inventory."""
    name: str
    unit_price: float
    quantity_on_hand: int = 0

    def total_cost(self) -> float:
        return self.unit_price * self.quantity_on_hand

该注释会从类上注释的类型隐式生成默认方法。我知道这不是你问题的答案(因为你实际上看不到生成的代码),但可能可以帮助解释你提出这个问题的原因。


欢迎来到SO,请阅读 https://stackoverflow.com/help/how-to-answer 以了解如何提高答案质量。 - blondelg
1
是的,那绝对是一个潜在的解决方案,同意。 - sparc_spread

1

选择class,然后执行以下操作之一:

  • Alt-Insert
  • 右键点击 -> 生成
  • 菜单 -> 代码 -> 生成

11
在生成的菜单中,唯一的选项是“覆盖方法...”,例如,它会生成一个具有标准默认体的__eq __(),该体的内容为return super().__ eq__(*args,**kwargs)。我想知道是否有一种方法可以根据已知的实例变量实际生成__eq __()和类似方法的实现。是否有这样的方法?(或者是我的PyCharm配置错误了,除了“覆盖”之外,还应该有其他选项吗?Intellij有其他选项。) - sparc_spread
仍然,这个答案是有道理的。 - vitaliis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接