1

Let's say I have the following class :

class Context:

    element_list = []

    @classmethod
    def add(cls, element):
        cls.element_list.append(element)

    @classmethod
    def remove(cls, element):
        cls.element_list.remove(cls.element_list.index(element))

This class is near of a Singleton class. The objective is to update element_list attribute anywhere in my program without passing a Context instance as parameter of my functions.

PyCharm signals me that I should define an __init__ method. But I do not want to create two different instances of this class. I was thinking about creating a dummy __init__ method like this :

def __init__(self):
    raise NotImplementedError("This class should not be initialized")

The question(s) is (are) : should I define an __init__ method ? if yes how ? instead of using classmethod implementation should I use a singleton class (see: Is there a simple, elegant way to define singletons?)

Community
  • 1
  • 1
FunkySayu
  • 7,641
  • 10
  • 38
  • 61
  • Why not just use a module for this? Create a module, use functions and make `element_list` a global. – Martijn Pieters Jun 26 '15 at 11:15
  • classmethods are bad, why not have an instance and pass list in the init? – matino Jun 26 '15 at 11:15
  • @matino: classmethods are *not* bad. They have excellent usecases. This may not be it however. – Martijn Pieters Jun 26 '15 at 11:16
  • @MartijnPieters I don't really want to use a module for this, cause it's not really adapted to my global program. I'd rather use a Singleton class than a module. – FunkySayu Jun 26 '15 at 11:17
  • Then just ignore PyCharm. But a module is the ultimate singleton, in Python. – Martijn Pieters Jun 26 '15 at 11:18
  • @MartijnPieters In which case do you think that the class method are more adapted ? I though it was the right way to use them – FunkySayu Jun 26 '15 at 11:19
  • You are just using a class to create a new namespace here and class methods enable that use. But classes ultimately are just instance factories so this use flies in the face of convention and expectation. – Martijn Pieters Jun 26 '15 at 11:22
  • Related topic to the question : http://stackoverflow.com/questions/12179271/python-classmethod-and-staticmethod-for-beginner – FunkySayu Jun 26 '15 at 13:33

1 Answers1

0
  1. The __init__ method is not mandatory. You should only define an __init__ method if you want to pass state to the instance being initialized. Looking at the code snippet you provided, it doesn't seem to be the case.

  2. There are a few ways (hacks) to implement the singleton pattern in python:

    However, I think those methods aren't pythonic and should be avoided for the majority of the cases.

    As others have said, you could always use python modules. Python modules are one of the most awesome features of the Python programming language. They can have state (variables), behaviors (functions) and within one Python process execution, a module will be loaded only once.

    This means that, in a directory structure like:

    .
    ├── bar.py
    ├── foo.py
    ├── main.py
    └── singleton.py
    

    You could do:

    # file: singleton.py
    element_list = []
    

    And from the rest of your application you could simply import and use it:

    # file: foo.py
    import singleton
    
    def foo():
        # ... do complex computations ...
        singleton.element_list.append('baz')
    

    # file: bar.py
    import singleton
    
    def bar():
        # ... do more complex things ...
        if 'baz' in singleton.element_list:
            print('baz')
    

    # file: main.py
    import foo
    import bar
    
    foo.foo()
    bar.bar()
    # OUTPUTS: 'baz'
    

    As you can see, besides being simple and more elegant, using the module gives you all the usual list utilities to interface with (for instance, you could do singleton.element_list[1:] or singleton.element_list + ['my', 'other', 'list'], and so on). If you wanted to do this your way, you would have to implement other classmethods.

Community
  • 1
  • 1
Gabriel Lima
  • 348
  • 3
  • 11