1

I have 2 files that run together, a ui file and a util file.

This is the UI file:

import util
class MainWindow(object):
    ...
    def method_context_callback(self, *args):
        if args[0] == 'M1':
            self.ctx = utils.M1Context(...)
            self.ctx.run_context()
        elif args[1] == 'M2':
            self.ctx = utils.M2Context(...)
            self.ctx.run_context()

This is the Util file:

class M1Context(object):
    def __init__(self):
        ...
    def run_context(self):
        # Do something when Method01 is used

class M2Context(object):
    def __init__(self):
        ...
    def run_context(self):
        # Do something when Method02 is used

Is there a need to make run_context methods in the utils.py as a staticmethod? In my UI, there are 2 buttons, one each for Method01 and Method02, where User can use the buttons anytime he/she liked while the UI is being active.

I asked this because while I was reading something online, it was mentioned that it can be considered. To be honest, I am not very familiar with @staticmethod as generally I wrote my code in this format.

How do I know when and in what sort of situations should I make it as a static method?

dissidia
  • 1,531
  • 3
  • 23
  • 53
  • Not Python, but [this answer](http://stackoverflow.com/questions/2671496/java-when-to-use-static-methods) should help you consider. – tyteen4a03 Mar 09 '17 at 23:34
  • Ah, I remember that article/post I read was talking/ using Python language... – dissidia Mar 09 '17 at 23:52
  • I highly recommend Raymond Hettinger's 46-minute PyCon 2013 talk, "[Python's Class Development Toolkit](https://www.youtube.com/watch?v=HTLu2DFOdTg)". He's one of Python's core developers, and his lectures are always fun as well as informative. This one demonstrates the "whys" behind many features of Python's classes, including `@staticmethod` and `@classmethod`. – Kevin J. Chase Mar 10 '17 at 01:50

3 Answers3

1

A static method allows you to use it without a class instance. A side effect of that is that the static method cannot use anything attached to self.

class Banana:
    def __init__(self, age):
        self.age = age

    @staticmethod
    def get_calories():
        return 88.7

    def get_age():
        return self.age;

Banana.get_calories()  # Is valid
Banana.get_age()  # will not be valid

banana = Banana(age=2)
banana.get_age()  # valid
banana.get_calories() # valid

As far as I'm aware it's not good practice to mix in static methods and normal ones in a single class, but there are situations where it might make sense.

Nether
  • 1,081
  • 10
  • 14
  • Hmm.. do correct me if I am wrong on this.. If staticmethod is going to be used, is `self` needed, eg. `def get_calories(self)`? – dissidia Mar 09 '17 at 23:57
  • @dissidia - no, because you wouldn't need to instantiate an obj to use a static method – ryugie Mar 10 '17 at 00:03
  • Yeah, we cannot use self variable inside of staticmethod, luckily we can still use attributes defined inside of the class including descriptor. – Menglong Li Mar 10 '17 at 00:14
  • Ok, I tried with either method - with or without the use of `@staticmethod`, my code still works. Hence my confusion on whether I should use it or not. – dissidia Mar 10 '17 at 01:19
  • If you'd like to be able to use the method without creating an instance of the class, add `@staticmethod` to it. If not, don't – Nether Mar 11 '17 at 16:14
1

There's no strict boundary about whether to use static method or not.

Regardless of the differences between the ways being called as a static method and a class method (you could save memory and be fast using static method cause you don't have to bind this method to a specific class instance).

Here I'll talk more about design patterns.

Ideally, static method means this function should be stateless, which declares that it should just act like a function, when passing same input each time, we got the same output. There's no inner state captured by the instance that can affect the logic and result of the static method.

So that's why in strategy design pattern, the strategy class usually be implemented as a so-called static class with a bunch of static methods.

As for your case, let's consider it in the following ways:

  • If you treat it like context, for context, as the name shows, each context should contain inner values and state. So static method here is not proper.
  • If you treat it like two different strategies, you should use static method.
  • So which is better: I suggest you combine the two design patterns together: use strategy to handle different logics, and use a new class called context to hold inner state and values to provide materials for strategy. Furthermore, your M1, M2 class should also have a base class, which can take the advantage of object oriented design.
from abc import ABCMeta, abstractmethod


class ContextBase(object):
    __metaclass__ = ABCMeta

    def __init__(self):
        pass

    @abstractmethod
    def run_context(self):
        print 'this is logic inside of base'

    @staticmethod
    def step_a():
        pass

    @staticmethod
    def step_b():
        pass

class M1Context(ContextBase):
    def __init__(self):
        super(M1Context, self).__init__()

    def run_context(self):
        super(M1Context, self).run_context()
        print 'logic inside of subclass'
        super(M1Context, self).step_a()
        super(M1Context, self).step_b()


m1 = M1Context()
m1.run_context()
Menglong Li
  • 2,177
  • 14
  • 19
  • Is `class MainWindow` not consider as a base class? – dissidia Mar 10 '17 at 01:20
  • Nope, MainWindow is just a client, which use your context instance. Base class means it act as a parent of ur context, and your context can reuse your base class common method or declaration. – Menglong Li Mar 10 '17 at 01:38
  • Added some sample codes, which is runnable, hoping that could help you a little bit. – Menglong Li Mar 10 '17 at 15:15
1

My personal rules are:

  1. if I have a method that is starting to get too long or harder to read, I will try to refactor it into smaller chunks. I may try to create a few other methods and split the logic among them. If any of them make no use of self but make sense outside the object, I will turn it into a function, otherwise I will keep it as a method and apply the @static_method decorator.

  2. in the rare occasions where a method should be called from the class, I will make it a class method: for example when I have something like MyClass.create_new_instance_from_json(json_string).

Paulo Scardine
  • 73,447
  • 11
  • 124
  • 153