48

I am writing a series of text menus. With the class and sub class below it runs with no issues. But I am reviewing my coding and I am wondering....is it ok that I didn't use def __init__(self) in the classes? Should I have placed the data members in def __init__(Self): such as self.images = (), self.options =()? If I did that then I could not use the abc module for restrains, correct?

class BaseMenu(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractproperty
    def options(self):
        pass

    @abc.abstractproperty
    def menu_name(self):
        pass

    def display(self):
        header = "FooBar YO"
        term = getTerminalSize()
        #sys.stdout.write("\x1b[2J\x1b[H")
        print header.center(term, '*')
        print self.menu_name.center(term, '+')
        print "Please choose which option:"
        for i in self.options:
            print(
                str(self.options.index(i)+1) + ") "
                + i.__name__
            )
        value = int(raw_input("Please Choose: ")) - 1

        self.options[value](self)

class Servers(BaseMenu):

    menu_name = "Servers"
    images = ()
    foo = ()

    def get_images(self):
        if not self.images:
            self.images = list_images.get_images()
        for img in self.images:
            print (
                str(self.images.index(img)+1) + ") "
                + "Name: %s\n    ID: %s" %
                (img.name, img.id)
                )

    def get_foo(self):
        if not self.foo:
            self.foo = list_list.get_list()
        for list in self.foo:
            print "Name:", list.name
            print "  ID:", list.id
            print

    def create_servers(self):
         create_server.create(self)

    options = (
        get_images,
        get_foo,
        create_servers
        )
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
dman
  • 10,406
  • 18
  • 102
  • 201

3 Answers3

38

Your code is perfectly fine. You don't have to have an __init__ method.

You can still use __init__, even with an ABC. All that the ABC meta tests for is if the names have been defined. Setting images in an __init__ does requires that you define a class attribute, but you can set that to None at first:

class Servers(BaseMenu):

    menu_name = "Servers"
    images = None
    foo = None

    def __init__(self):
        self.images = list_images.get_images()
        self.foo = list_list.get_list()

Now you can set constraints on the ABC requiring that a images abstract property be available; the images = None class attribute will satisfy that constraint.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
13

Your code is fine. The example below shows a minimal example. You can still instantiate a class that doesn't specify the __init__ method. Leaving it out does not make your class abstract.

class A:
    def a(self, a):
        print(a)
ob = A()
ob.a("Hello World")
IniasP
  • 125
  • 1
  • 6
Chandan
  • 147
  • 1
  • 3
  • 15
    Please give context to your code. Answers containing code only without explanation and/or comments are not very useful. – pfabri Mar 16 '19 at 15:40
0

Just to add to the other answers, omitting __init__() could be useful when we want to call only certain methods of a class because instantiating an object repeatedly could become expensive computationally in some use cases.

For example, suppose you have a calculator application and Python acts as an API and will provide the results from the calculator to the client. Consider the following function in main.py:

import operations

def main():
  ### Some code here ###
  
  result = operations.Operations.calculate_value(value_1)
  # "Operations" is the name of the class in the module.
  # "value_1" is the data being sent from the client.
  
  ### Some code here ###

  return result

For simplicity, I have not included the boilerplate for handling API calls. main() will be called every time a new request needs to be processed by the server. So, creating an instance of the class every time when a request arrives will be expensive if the number of users accessing it is high.

Considering the above example, we can define "Operations" in operations.py as shown below:

class Operations:
  # Omit __init__() since we will be using only class and static methods.

  # You can use @staticmethod decorator as well here
  # if you don't have any class variables or if you
  # do not need to modify them.
  @classmethod
  def calculate_value(value):
    ### Some code here ###
    
    calculated_value = value + 1
    
    ### Some code here ###

    return calculated_value
  • Here is a link for anyone who wants to know about staticmethod and classmethod decorators: https://realpython.com/instance-class-and-static-methods-demystified/. – chess_madridista Jul 21 '22 at 21:25
  • This doesn't make any sense, in this case, you simply *shouldn't have a class at all*. A class with only static methods *shouldn't be a class*. While sometimes people like to use classes as sort of simple namespaces for, for example, configuration, generally if you aren't going to *instantiate your class* then it probably shouldn't be a class. In this case, it definitely shouldn't be – juanpa.arrivillaga Jul 21 '22 at 21:44
  • 1
    @juanpa.arrivillaga But if the application is large and if we use classes for better maintainability of the functions, what is the harm in having static methods. Is it written somewhere in the documentation that you always need to create an instance of a class if it is defined? If you could please clarify more on what you are saying, then maybe I might be able to grasp it since I am still a noob :). – chess_madridista Jul 22 '22 at 08:30
  • What value is the class adding? What better maintainability? – juanpa.arrivillaga Jul 22 '22 at 15:03
  • This is just an example. I also mentioned in the answer that this approach can be used in the cases of big applications. Suppose you have 10 to 15 classes. Are you going to store all those classes in the same file? Now, there might be a case where we might need to use only specific functions of a class to perform some computation. If that computation is being performed repeatedly, there is no need to create an instance of the class and we can just call the required function. – chess_madridista Jul 22 '22 at 18:23
  • Oops, I didn't mention the big application part in my answer. My apologies! – chess_madridista Jul 22 '22 at 18:26
  • 2
    No. Instead of a class you would just use a module. A class with only static methods should just be a module. The size of the code base is irrelevant. [Here, check out this answer](https://stackoverflow.com/a/38759051/5014455) I wrote to a question specifically about this. – juanpa.arrivillaga Jul 22 '22 at 18:28
  • Yeah, correct! I was referring to using those classes as modules only. As stated in the answer, I have imported "operations" module. I should have been more articulate about it. Thanks for the link to your answer. I will check it out. – chess_madridista Jul 23 '22 at 05:06
  • @juanpa.arrivillaga I read your answer and some others as well on the post which you shared. Is there any significant difference in performance if I use independent functions (without any class) instead of "@staticmethods" inside classes in modules? I am assuming "@staticmethods" decorator was created specifically to use in modules. Or was it created to have only some methods inside a class as static? – chess_madridista Jul 23 '22 at 07:42
  • `staticmethod` doesn't make sense unless it is in a class. – juanpa.arrivillaga Jul 23 '22 at 21:21
  • No, I didn't ask whether it should be inside or outside classes. I asked which approach is better to use in case of modules, using functions or static methods (assuming there is an obvious difference between functions and methods.). Does it depend on use case? – chess_madridista Jul 24 '22 at 05:12
  • What do you mean in the case of modules then? Modules don't contain static methods. I mean they can, but that would be strange and not very useful. Unless you mean they contain a class or classes with all static methods? I already made my view on that clear. I think it should just be modules with functions instead of that. – juanpa.arrivillaga Jul 24 '22 at 18:59
  • 1
    Performance-wise, `module.class.method()` would require one more attribute access, so a minor performance penalty compared to `module.function()`, but performance isn't the issue really. – juanpa.arrivillaga Jul 24 '22 at 19:00
  • Okay, so I will give you a bit of a context. I am creating an expenses calculator for roommates. I am organising the project in such a way that each individual operation (such as if a person can checkout or not, if a new person can enter the house or not, etc.) is in a separate module. So, the reason why I am using a class in modules is that I have made multiple functions for abstraction and encapsulation purposes. And for the functions which should not be called directly in the main.py, they are being made private. So, that's why I am not using separate functions inside the modules. – chess_madridista Jul 25 '22 at 07:28