5

Generally speaking in canonical OOP situations, the rule of thumb is to write your classes with the least access as necessary. i.e. only make public only what is necessary, make protected only what is necessary, etc etc. (There are exceptions and what I describe does not always apply. FWIW, I find the idea of "least access as necessary" to be useful in more canonical OO C++/Java situations.)

However in Python, you don't have strict access modifiers like public, protected, private, etc. Python has pseudo protected and pseudo private in the form of single _ and double __ underscores for your object fields and methods.

In more "canonical OO"[1] Python situations, what is the rule of thumb for default access modifiers?

Is the rule of thumb to restrict more (like in C++/Java) and qualify all fields/methods with __ until there is a requirement/design/API need to make it public or protected?

Or is the rule of thumb to start with all your python fields/methods as public and restrict them as needed?

I have seen some who default to protected with _ and use pylint to catch breaking encapsulation. I can also see others who would default to private. And I'm sure there are still others who default to public.

[1] I use the term "canonical OO" to refers to more of what I would call textbook OO programming theory/situations. In my experience real programming often differs from textbook OO or canonical OO programming theory.

12
  • 2
    I'm not sure if there is a canonical answer, but as a rule of thumb, I prefix every attribute by an underscore, and I expose them using properties if necessary. I also believe it's a bit misleading to talk about protected and private in Python's context because I don't think it relates very well to the same concept in, say, Java. Commented Apr 6, 2017 at 12:19
  • 2
    Have you read the style guide? The naming section covers all of this. Also we're all consenting adults here and everything is public really (foo.foo, foo._bar and foo.__Foo_baz).
    – jonrsharpe
    Commented Apr 6, 2017 at 13:16
  • 2
    @VincentSavard hopefully not in violation of "For simple public data attributes, it is best to expose just the attribute name, without complicated accessor/mutator methods"!
    – jonrsharpe
    Commented Apr 6, 2017 at 13:22
  • 1
    @TrevorBoydSmith You asked for a canonical answer. I can only provide an answer based on my own experience, and as you surely know, if this is what you're actually looking for, your question is primarily opinion-based and should be closed. Commented Apr 6, 2017 at 17:06
  • 1
    -1. This question has been asked a dozen times before. Python doesn't have access modifiers and you shouldn't try to emulate them
    – mrr
    Commented Apr 11, 2017 at 22:41

1 Answer 1

5

First of all the double underscore (sometimes called dunder) is not meant to be private, but rather a name mangling strategy to avoid certain conflicts. Check this talk of Raymond Hettinger (one of the Python core developers... and the the whole talk is totally worth the time). I personally have never ever needed the dunder/name mangling.

So, the question is rather about when to "protect" by using one underscore, and when not to. My rule of thumb for this is: keep things as private and simple as possible.

Say you have a Stone class with for the moment only attributes for material and weight. A recipe could go like this:

  1. Default to underscoring everything: _weight and _material

  2. Think veeery carefully about the class API and answer this question: what members are to be exposed?. Then convert these members to public by removing the underscore. Let's say _weight gets converted to weight

  3. As time goes by, you might need to convert a you-shouldn't-care member, into a full public member. No shame about it, just remove the underscore and refactor the class code to match the new name, e.g. _material > material. Don't create a @property to access the previous attribute, it is just more complex.

  4. Again, as time goes by, it can be that one of the attributes gets dependent on another, let's say that weight becomes dependent on volume and density, but worry not! now it is time to convert the weight attribute into a @property and keep a single source of truth without breaking existing code.

Not the answer you're looking for? Browse other questions tagged or ask your own question.