0

I was reading this link about using getters in Python, quote:

The Pythonic way is to not use them. If you must have them then hide them behind a property.

That same page includes various examples, but my question is, if getters are not the Python way, how would I indicate to someone reading my code that a variable should be read-only after construction.

Suppose I have the following class:

class Car:
    def __init__(self, ID, name, tire, engine):
        self.ID = ID
        self.name = name
        self.tire = tire
        self.engine = engine

    def __str__(self):
        return "ID: {0} Name:{1} Tire: {2} Engine: {3}".format(self.ID, self.name, self.tire, self.engine)

If I wanted to indicate to another developer that self.engine is read-only after being set in the constructor, how would I do so? In orders words, if clients violate the rule, and attempt to set it, it's there problem if the implementation of self.engine changes(for example, from object of the class Engine to Dictionary).

  • 1
    Give it a single underscore prefix e.g `self._engine`. It wont stop others from using it but it is a clear indicator its private. You can also use a double underscore prefix to have python mangle the name (see [here](https://stackoverflow.com/questions/1301346/what-is-the-meaning-of-a-single-and-a-double-underscore-before-an-object-name) for details. – Paul Rooney Dec 08 '17 at 02:30
  • 1
    @PaulRooney No, the underscore indicates that the variable shouldn't be accessed from outside of the class at all (except from derived classes). – Michael Butscher Dec 08 '17 at 02:31
  • I don't mind if they get it, just that they aren't allowed to set it afterward(i'm aware there is nothing really stopping them from doing so). –  Dec 08 '17 at 02:32
  • @MichaelButscher I'm not clear on where your disagreement lies. – Paul Rooney Dec 08 '17 at 02:35
  • @S.R. Right. If you don't want to use properties you could list the accessible variables in the doc-string of the class and mention something like "(read-write)" or "(read-only) for each. – Michael Butscher Dec 08 '17 at 02:36
  • @PaulRooney - He saying the underscore should be treated as protected variables –  Dec 08 '17 at 02:37
  • @S.R. and so was I, so it would seem there is no disagreement on that point. – Paul Rooney Dec 08 '17 at 02:38
  • @PaulRooney The OP wanted a read-only variable just by documentation (without `property`) but without property, an underscored variable is by convention meant to be `protected` in Java/C++ notion. – Michael Butscher Dec 08 '17 at 02:39
  • Why not just define a _docstring_ for your property and treat the users of your class as consenting adults? – zwer Dec 08 '17 at 02:40
  • @zwer - I think you've got it, any attempt to set it after being warned with the docstring is there problem, not mine. –  Dec 08 '17 at 02:42
  • I think the quote from the link is just wrong (or poorly worded). Properties are the Pythonic way and they need of course a hidden getter (and maybe setter, deleter) function behind it. – Michael Butscher Dec 08 '17 at 02:46
  • @MichaelButscher - Agreed, that being said I selected the answer below on how to use them. Thanks! –  Dec 08 '17 at 02:47

1 Answers1

2

You can use the @property decorator and not define a setter to communicate that engine should not be modified:

class Car(object):
    def __init__(self, ID, name, tire, engine):
        self.ID = ID
        self.name = name
        self.tire = tire
        self._engine = engine

    def __str__(self):
        return "ID: {0} Name:{1} Tire: {2} Engine: {3}".format(self.ID, self.name, self.tire, self.engine)

    @property
    def engine(self):
        return self._engine

Note that the user can still go around the property and set _engine directly.

Note that the @property decorator only works with new style classes.

Galen
  • 1,307
  • 8
  • 15
  • the `@properly` keyword will work with classes even if they don't inherit object, at least in Python 3 anyway. As stated in my question and the link `@property` is not the Python way of doing it apparently. –  Dec 08 '17 at 02:38
  • 2
    @S.R. no, you are not understanding that link. Properties are the Pythonic way. – juanpa.arrivillaga Dec 08 '17 at 02:41
  • @S.R. I think the answer you linked is referring to defining methods like `get_thing` and `set_thing`, not using `@property`. The documentation for this facility basically describes this use case: "A typical use is to define a managed attribute x". See the specific example for the read only property `voltage`. – Galen Dec 08 '17 at 02:42
  • @Galen - I think your right, I've been using `property` this way as described by you and the docs, but seeing that other link made me question if I was doing the right thing. –  Dec 08 '17 at 02:45
  • 1
    @S.R. In Python 3, all classes are new style classes and happen to inherit from `object`. Old style classes were removed. I will edit my answer to avoid confusion. – Galen Dec 08 '17 at 02:48