133

I want to order methods in a Python class, but I don't know what the correct order is.

When I extract methods in Eclipse with PyDev, Eclipse puts the extracted method on top of the modified method. But this puts the lower level details before the higher level details. According to Uncle Bob, I should do the opposite, so that my code reads like the headlines of a newspaper. When I program in Java I just follow his advice.

What is the best practice for Python?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
zetafish
  • 2,342
  • 4
  • 18
  • 19
  • 11
    There isn't a best practice. Do what makes the most sense - important stuff near the top is a good idea, and consistency is generally a good thing. PEP-8 doesn't mention this, and if it were to be set in stone, that's where it would be. – Gareth Latty Apr 23 '12 at 23:04
  • 6
    And even PEP8 isn't always set in stone. – Ignacio Vazquez-Abrams Apr 23 '12 at 23:06
  • 1
    I usually do it by group on the functionality (get, set, etc) – CppLearner Apr 23 '12 at 23:11
  • 2
    It's important to note that the order of method functions can be arbitrary, because a class declaration is only _defining_ its method functions, not _invoking_ them. This allows the class method routines' source code to successfully use method functions that will be defined later on down in the listing. – DragonLord Jun 17 '20 at 19:17
  • Somewhat related (not a duplicate): *[Enforcing method order in a Python module](https://stackoverflow.com/questions/7906187/)* – Peter Mortensen Jan 14 '22 at 20:18
  • (This was a top search engine hit looking for a way to let [Pylint](https://en.wikipedia.org/wiki/Pylint) check for some order of methods (instead of having to write a custom script) - it is an opinionated linter after all - `site:stackoverflow.com Pylint Python method order`.) – Peter Mortensen Jan 14 '22 at 20:25
  • 1
    How was this never closed as opinion-based? – chepner Jan 16 '22 at 15:05
  • 1
    The question isn't opinion based. The answer is: "It is opinion based", but that answer isn't opinion based either. – 00prometheus Apr 06 '23 at 15:28

4 Answers4

123

As others have pointed out, there is no right way to order your methods. Maybe a PEP suggestion would be useful, but anyway. Let me try to approach your question as objectively as possible.

  • Interfaces first: Public methods and Python magic functions define the interface of the class. Most of the time, you and other developers want to use a class rather than change it. Thus they will be interested in the interface of that class. Putting it first in the source code avoids scrolling through implementation details you don't care about.

  • Properties, magic methods, public methods: It's hard to define the best order between those three, which are all part of the interface of the class. As Ethan Furman says, it's most important to stick with one system for the whole project. Generally, people expect __init__() to the best first function in the class so I follow up with the other magic methods right below.

  • Reading order: Basically, there are two ways to tell a story: Bottom-up or top-down. By putting high-level functions first, a developer can get a rough understanding of the class by reading the first couple of lines. Otherwise, one would have to read the whole class in order to get any understanding of the class and most developers don't have the time for that. As a rule of thumb, put methods above all methods called from their body.

  • Class methods and static methods: Usually, this is implied by the reading order explained above. Normal methods can call all methods times and thus come first. Class methods can only call class methods and static methods and come next. Static methods cannot call other methods of the class and come last.

Most of these rules are not Python-specific by the way. I'm not aware of a language that enforces method order.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
danijar
  • 32,406
  • 45
  • 166
  • 297
  • 2
    Usually a language does not enforce ordering. But some languages have common conventions. E.g. [C# StyleCop](https://github.com/StyleCop/StyleCop) has a strict ordering rules. For Java see http://stackoverflow.com/questions/4668218, etc. – xmedeko May 04 '17 at 14:13
  • 2
    class methods: these are often used as constructors and then they do typically call `__init__` explicitly (in combination with `__new__`) or implicitly (through the default constructor), so that would be a reason to place them together with `__init__`. (Although I've never seen them placed _before_ `__init__`.) – oulenz Jul 16 '19 at 13:05
23

There is no one correct order. Pick a system and stick with it. The one I use is:

class SomeClass(object):

    def __magic_methods__(self):
        "magic methods first, usually in alphabetical order"

    def _private_method(self):
        "worker methods next, also in alphabetical order"

    def a_method(self):
        "then normal methods, also in alphabetical order"
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Ethan Furman
  • 63,992
  • 20
  • 159
  • 237
  • 4
    What's your preference for staticmethods, class variables, and @property decorated methods? – John Mee Sep 13 '12 at 04:56
  • 1
    @JohnMee: class variables I put before anything else; my folding method hides the `@staticmethod`, `@classmethod`, `@property`, and any other `@decorator` lines so I use the type of the method to determine where it goes (with the exception that properties tend to go between `_private_methods` and `normal_methods`). – Ethan Furman Sep 13 '12 at 16:22
  • So if the order basically goes from very private "magic" methods to private to normal methods, does that mean `@classmethod`s come next (`@classmethod def a_class_method(cls)`) then `@staticmethod`s (`@staticmethod def a_static_method()`)? At least that's the policy as I understand it... **(without my IDE folding anything because I don't like that)** – Kawu Jul 23 '14 at 08:19
2

I do something similar to Ethan that I saw in Django's source, where the main difference is big "############" block comments to delimit the areas.

For example,

class SomeClass(object):

    #################
    # Magic Methods #
    #################
    def __magic_methods__(self):
        "magic methods first"

    ##################
    # Public Methods #
    ##################
    def a_method(self):
        "then normal methods, in order of importance"

    ###################
    # Private Methods #
    ###################
    def _private_method(self):
        "then worker methods, grouped by importance or related function"

Obviously this is less useful for smaller classes.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matt Luongo
  • 14,371
  • 6
  • 53
  • 64
  • 26
    But I can see that they're magic, public or private. I actively dislike such blocks of comments, myself; I can look at the code folded if I want to see a list of them all. Having a comment above a particular block of functionality-related methods is something I'd do, but for this type of comment--that's what the method names tell me. – Chris Morgan Apr 23 '12 at 23:38
  • 1
    Again, I only do this for larger classes. I find it's easy to confuse magic methods with semi-private (_) and name-mangled (__) methods. – Matt Luongo Apr 24 '12 at 15:03
  • 1
    I was mid-edit removing the ugly `####` blocks when I realized you'd put them there *on purpose!* I do agree with the *order*, though, which is what this question is about. I'd recommend removing the `####` from this example since it doesn't pertain to the scope of the question and your example is of a small class, for which you wouldn't use `####` anyways. :-) – Mateen Ulhaq Apr 08 '18 at 07:04
  • I've removed the `####` for you; revert if necessary. – Mateen Ulhaq Apr 08 '18 at 07:06
  • 5
    @MateenUlhaq please refer to the second and fifth guidelines displayed on the editing screen: "clarify meaning without changing it" and "*always* respect the original author". (Note that these are meant to be applied unconditionally, with no respect to the editor's own opinion.) The whole and only point of this answer was to display those ugly comment blocks; without them, it says the exact same thing as Ethan's answer and there is no point for it to be here. You even did acknowledge that the blocks were there "*on purpose*" -- knowing this, why would you go and remove them? –  Apr 09 '18 at 00:52
  • 1
    @M.I.Wright I thought it outside the scope of the question. As you can see, [rev2](https://stackoverflow.com/revisions/10289697/2) still contains material that answers the question differently from Ethan's, with a different ordering (and subordering!). Nevertheless, rolled back. – Mateen Ulhaq Apr 09 '18 at 00:58
2

The code

class Bar(_Foo):
    pass

class _Foo:
    pass

raises an exception since the class _Foo has to be defined before it is used. You can find similar exception-raising example for functions too:

def bar(f=_foo):
    pass

def _foo():
    pass

Given these examples it makes sense to generally define private classes and functions before the public ones. That's why it makes sense to keep the consistency and to define also private methods before the public ones.

Jeyekomon
  • 2,878
  • 2
  • 27
  • 37