3

One of the things that has confused me when studying best software engineering practices is how to handle methods in classes that don't alter or otherwise interact with the state.

In this article I like how the author discusses the separation of data and logic. But in trying to apply this in practice, I have cases where I have an odd-out function outside the class that doesn't change the state of the object but isn't really relevant outside the object.

For example:

def inspect_color(color):
    if color == 'brown':
        return 'Similar to chocolate'

class Dog(object):

   def __init__(self, color):
       self.color = color

   def play_in_mud(self):
       self.color = 'brown'
       results = inspect_color(self.color)

vs.

class Dog(object):

   def __init__(self, color):
       self.color = color

   def play_in_mud(self):
       self.color = 'brown'
       results = self.inspect_color()

    def inspect_color(self):
        if self.color == 'brown':
            return 'Similar to chocolate'

Is there a general software engineering principle or best practice (from any reasonable paradigm) that suggests which of these approaches should be followed? For multiple reasons my intuition tells me that the top one is better, except doing this: inspect_color(self.color) bothers me, so I am unsure. I did some reading but didn't find a clear answer on best practices for cases like these.

jstaker7
  • 1,226
  • 4
  • 15
  • 29
  • 1
    This is probably off-topic because it is based too much on opinion, but for what it's worth, it is my opinion that the first one is better. Class bloat is baaaad. – juanpa.arrivillaga Jan 18 '17 at 23:06
  • Thanks for the thoughts. Any suggestions on a better place for the question? I was hoping there was a best-practice that was less opinion based, but good point. – jstaker7 Jan 18 '17 at 23:09
  • 2
    Why does this bother you? — I used to think the same, but the reason was just irrational conditioning that “good” OOP meant always writing `obj.method()`. And that’s simply not true. There’s no objective reason it’s bad, other than habit (and, to be honest, the fact that it creates a non-uniform syntax for calling functions on things; but that is true in Python anyway, so it doesn’t apply here). – Konrad Rudolph Jan 18 '17 at 23:29
  • @jstaker7 Can you change the question so that's it's not "which is better?" You provide a specific example but as another commenter said, this is totally opinion based. – wheaties Jan 19 '17 at 21:09
  • Sure thing. Just made changes to make it more specific and less opinion based. – jstaker7 Jan 19 '17 at 22:14

2 Answers2

2

That is what a staticmethod is good for.

A static method does not receive an implicit first argument.

class Dog(object):

    def __init__(self, color):
        self.color = color

    def play_in_mud(self):
        self.color = 'brown'
        results = self.inspect_color(self.color)
        return results

    @staticmethod
    def inspect_color(color):
        if color == 'brown':
            return 'Similar to chocolate'

You can use it just like a function:

>>> Dog.inspect_color('brown')
'Similar to chocolate'

and in your method:

>>> dog = Dog('red')
>>> dog.play_in_mud()
'Similar to chocolate'
Mike Müller
  • 82,630
  • 20
  • 166
  • 161
  • 5
    I don’t think (or rather, I don’t agree) that this is a good use for a static method. The method has nothing to do with `Dog`; only with `color`. It simply doesn’t belong in `Dog`. It *may* belong in the same module but certainly not in the class. – Konrad Rudolph Jan 18 '17 at 23:32
  • Maybe this due to the example but the alternative the OP has are either an external function or an instance method with `self` as first argument. Putting both together would make a static method, I think. – Mike Müller Jan 18 '17 at 23:37
  • 2
    ...or just use an external function. – juanpa.arrivillaga Jan 18 '17 at 23:48
0

This isn't really a full answer, but I don't quite have a high enough rep to just make a comment. I'm no expert on OOP best practices, but my gut feeling is that the colour analysis function would be best implemented as an interface, because that way the specifics of the implementation can be left up to the given class, but there can be some degree of standardisation across classes.

Turns out Python doesn't really do interfaces though apparently (according to this). Others who know better about the SOLID principles could advise better than I.

Community
  • 1
  • 1
Jarak
  • 972
  • 9
  • 16
  • You're right, OP's example is contrived and `inspect_colour` would make sense as a function defined elsewhere, so as to avoid violation of the Single Responsibility Principle (**S**OLID). I use static methods in Python just like I'd use them in Java or C# - to implement functionality specific to a class that does not need to reference the instance (i.e. `self`). – Tagc Jan 19 '17 at 20:59