0

I'm curious about the recommended way to return a value for instance methods in Python. I'm sorry if this comes across as a rather trivial question, but I can't seem to find a proper answer on google/sx/so.

Option 1:

class Cla:
    def __init__(self):
        self.var = False

    def _inst_mtd(self):
        var = True
        return var

    def calc_var(self):
        self.var = self._inst_mtd()    # or in init if desired

    def return_var(self):
        return self.var

Option 2:

class Cla:
    def __init__(self):
        self.var = False

    def _inst_mtd(self):
        self.var = True

    def calc_var(self):
        self._inst_mtd()

    def return_var(self):
        return self.var

Option 3:

class Cla:
    def __init__(self):
        self.var = False

    def _inst_mtd(self):
        self.var = True
        return self.var

    def calc_var(self):
        self.var = self._inst_mtd()

    def return_var(self):
        return self.var

The intention of _inst_mtd is to calculate a value for self.var. A separate public method to return self.var will provide the return function to an outside caller . _inst_mtd is meant to be called within the class, perhaps in a loop, and perhaps with a public method calc_var if for instance it'll take a while to run .

My concerns are that 1 might result in confusion between local and instance variables, if the whole point of _inst_mtd is to modify self.var and not actually deal with another variable called var. For 2, I'm under the impression that (considering only _inst_mtd) this constitutes a side-effect, which should be avoided? But 3 just seems unnecessary, although it does work well with return type annotations, especially when the type (not recommended) or elements within are changed in _inst_mtd.

quamrana
  • 37,849
  • 12
  • 53
  • 71
Melvin
  • 1,530
  • 11
  • 18
  • Disclaimer: This was first posted in Software Engineering, but no one responded there. Please do point me to possible duplicates, I can't find any that talk about this specific example when I tried searching. Post has been taken down there to avoid double-posting. – Melvin Jan 26 '18 at 16:19
  • 2
    I python you do not need any method of type `return_var(self)`. All class variables are public. – mrCarnivore Jan 26 '18 at 16:20
  • I was thinking that `return_var(self)`, or `get_var(self):` would be a given! – quamrana Jan 26 '18 at 16:21
  • Option 3 is definitely wrong since you update `self.var` in two places. – quamrana Jan 26 '18 at 16:22
  • Hi mrCarnivore, yes I'm aware we can simply do a `Cla.var` to retrieve the value of var, it's perhaps to follow it up with an interface later on, which will call `return_var`, allowing me to replace `self.var` with something else later on? – Melvin Jan 26 '18 at 16:23
  • Hi quamrana: Given, meaning? Erm, I should not put it inside the question code sample, or...? Sorry I'm not really familiar with how much to put inside, I got rather frequent feedback in the past to put more of what I intend to do in the code sample, but there's also the point about putting only enough for it to run, so :\ – Melvin Jan 26 '18 at 16:32
  • Option 3 helps with return type annotations though. I felt that it's pretty lame to update it twice too (the second call essentially did nothing), but then I got flamed by someone about using `var` when I mean `self.var`. But, option 2 don't play well with type annotations, since it end up being a `_inst_mtd()` line call in the class. Would appreciate any tips and advice! – Melvin Jan 26 '18 at 16:34

2 Answers2

2

You are putting too much emphasis on public/private access. In Python every member of any instance (method, variable, etc.) is publicly available. So, you wouldn't even usually bother to write special getter or setters. Instead:

c = Cla()
c.var = 42
print(c.var)

is perfectly acceptable. If you still would like to hint to other programmers that the variable should be private and not messed with, you would usually prefix it with a single underscore: self._var. However, this is only a convention. For more, see https://stackoverflow.com/a/1301369/1269892

alisianoi
  • 2,003
  • 3
  • 31
  • 46
  • Hi! Thanks for your response. Imagine if this is called in some client code, and some day later I decide I want `return_var` to return something else apart from `self.var`. Does providing an access method not aid in that later on? – Melvin Jan 26 '18 at 16:28
  • 1
    If you are creating some kind of an API, then your client classes should of course have some kind of a guarantee that the code will still work. So, if it is something very simple which can be stored as a variable and the name of that variable will not change, then go for the simple `self.var`. This is seldom the case though, so you could choose to create a method `self.compute_stuff()`. If you create a method, it is your responsibility to choose a good name and not change the return value. If you do change thigs, it is your responsibility to let your clients know. – alisianoi Jan 26 '18 at 16:32
  • Hmm that is very true. I'm sorry that the `return_var` naming is somewhat confusing. I'm under the impression that we should build our code such that it's 1. easily refactorable and 2. it'll not affect calling code? Hence the preference for a `return_func`, I received quite a bit of feedback during PR for that :D what in your opinion are the pros and cons of using a return func vs simply self.var? – Melvin Jan 26 '18 at 16:40
  • 1
    If you have something very simple (just storing some value), then imo you don't need methods. However, if you need to return something that should be recomputed often or takes a long time to recompute, you should have a method. Also, if a "verb" makes more sense in the name, it should be a method. If a "noun" and it's simple -- just a variable. – alisianoi Jan 26 '18 at 16:57
  • 1
    @Melvin idiomatic Python doesn't use getters and setters. [Read this](https://www.python-course.eu/python3_properties.php). Instead, you use properties, but only if you decide to go back and control access later. – juanpa.arrivillaga Jan 26 '18 at 17:13
  • @juanpa.arrivillaga oh I've only used properties within the context of descriptors when dealing with (meta)classes. Thanks, I learnt something else today :) – Melvin Jan 26 '18 at 17:30
2

Of the three, I think Option 2 makes most sense, since each method is clear in its role. But if _inst_mtd really doesn't need the internal state, as in Option 1, then you should probably just make it a function outside of the class. In Python, using getters just in case you might someday need them is generally considered the wrong way, because it is a superfluous complication most of the time. Also, you can always extract the internally-used method from the public method if and when needed. Simplicity where you can keep it is usually worth more than being engineered for hypothetical future needs.

class Cla:
    def __init__(self):
        self.var = False

    def calc_var(self):
        self.var = True

instance = Cla()
instance.calc_var()
value = instance.var
Derek Veit
  • 3,650
  • 2
  • 16
  • 15
  • Oh ok, yeah as of now 1 might as well be a static method, I'm intending for it to use something for self, yes I should have added it in the question, sorry >.< just to verify, in your example, I'll call it with `calc_var(Cla())`? 2 it shall be then :) thanks! – Melvin Jan 26 '18 at 17:03