26

I am a PyCharm newbie but a long-time IntelliJ user. In IntelliJ, when you are writing a class definition, the IDE can automatically generate a constructor, equals() method, and hashCode() method based on the instance variables. This is good not just for saving typing, but for preventing inadvertent errors and for automatically throwing in some equals() and hashCode() best practices.

I was hoping PyCharm could do the same, given that the products are from the same company. After much Googling and scouring of the documentation, I couldn't find anything for __eq__() or __hash__(). Granted, Python instance variables are not explicitly specified, but I was hoping the generator could follow a convention like offering all __init()__ parameters as potential instance variables. As for __init__(), I found something that will automatically add instance variable settings into the __init__(), but this approach seems more cumbersome than just typing, and it doesn't even add the instance variables as parameters to the __init__() signature.

Am I missing anything in the documentation, or perhaps there is a plugin that can do this?

Update: to be clear, I am looking for something that generates the actual implementations of these methods. That is, if I had a class called Point, and PyCharm knows my class has x and y instance variables, then it would automatically generate this for the __eq__() method:

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

The equivalent is easily done in IntelliJ.

3 Answers 3

12

You can create a Live Template

Under File->Settings->Editor->Live Templates Look for Python Click + to add, I then name mine "class" and make sure to add a context in the gui for Python files.

The Template Text :

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$

I left my "Options" -> "Expand with" section set to "Default (Tab)" After this point, when you type "class" you can use Tab auto-complete to insert the live template. Your cursor will be bounced into any section included as a variable in the Live Template Text.

More complicated, i.e. list type, variables don't appear to be supported by LiveTemplate. For instance, conditionals in the live template text, or list expansions, don't appear to be available.

Sign up to request clarification or add additional context in comments.

5 Comments

I indented class body and added def to each statement, and it ran successfully. However it does not generate the actual bodies of these methods - unless I am using it wrong?
Thanks, I've updated my answer to fix the syntax, how embarrassing. In the example above, I've only placed in the body of these methods the keyword pass, you can write in anything you like, and it'll put that in place, however, making those bodies universal is a tricky problem, I think. Can you give an example of what you'd like a general purpose __hash__() to be, for example ?
No prob. For __eq__(), I am looking for something like the example I added to my OP. For __hash__(), the implementation shown in this question looks good - calling hash() on a tuple of the same things compared in __eq__(). The problem is I don't think the PyCharm live template language is itself rich enough to iteratively generate blocks of code based on variable input. I looked and looked but I still could be mistaken.
@sparc_spread I've expanded as much as I can on the __eq__() method, in order to demonstrate a greater depth of use in the LiveTemplate system, but I think you're right about iterative generation. So, in the example of _eq above, I only made a single eq_field, as opposed to comparing against both self.a and self.b, for the reason that the variable types declared in the LiveTemplate help system don't appear to show any documentation that can work that out.
I agree, I think this is about as far as we can take it. It's too bad, this is really easy to do in IntelliJ without live templates, via the Code...->Generate menu functionality. Anyway unless something new comes along in PyCharm 4.5, I believe yours is the answer. At least we've automatically generated the portion of __eq__() that follows the best practice of returning NotImplemented if the compared classes are different.
3

Maybe the concept of data classes may also be interesting to you?

https://docs.python.org/3/library/dataclasses.html

Here's the example from the documentation:

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

The annotation implicitly generates default methods from the annotated types on the class. I know this is not an answer to your question (because one can not actually see the generated code) but could possibly help with the reason why you are asking.

2 Comments

Welcome to SO, please read stackoverflow.com/help/how-to-answer to see how to improve anwser quality
Yes that definitely is a potential solution, agreed.
1

Select the class and then do one of:

  • Press Alt-Insert
  • Right Click -> Generate
  • Menu -> Code -> Generate

2 Comments

The only option in the resulting menu is Override Methods..., which produces, for example, an __eq__() with a standard default body of return super ().__eq__ (*args, **kwargs). I am wondering if there is a way to actually generate the implementation of __eq__() and similar methods based on the known instance variables. Is there a way to do this? (Or is my PyCharm misconfigured and there should be more options besides Override Methods...? Intellij has other options besides Override.)
Still, this answer makes sense.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.