python: class with staticmethods vs module with global variables
Asked Answered
L

1

8

I'm working on this Python module, which compounded from several files. Few of those files are actually independents, and meant to do a very specific job. I know for a fact that there will be only one instance of those files (modules?), and no more, since this kind of job is sequentially, and needed only once.

Let's take for example this CXXParser module I'm currently building:

The routine is simple and clear - take a c++ file, parse it, and 'transform' it to something else. Since I come from c++ world, I immediately started to look for static methods and singletones in Python. For the use of this example, I have 'public' parse function, and many 'inner' functions of this module, which actually parsing the file.

I want to know, what is the 'Pythonic' way to do it? I started to look around for the correct way to do it, but only got confused. Since I thought about singletone - I saw this question, and from reading the answers I started to implement it on module-level. But, then again, I watched several videos of Raymond Hettinger, Python core developer, and he mentioned - few times - that global variables are bad, and it's better to use class-level variables.

These are the two options I'm currently facing:

A. Use a class with classmethods:

#cxxparser.py
class CXXParser(object):
    filename = ''
    cflags   = ''
    translation_unit = None

    def __init__(self, filename, cflags = None):
        super(CXXParser, self).__init__()
        filename = filename
        if cflags:
             cflags = cflags

    @classmethod
    def get_tu(cls):
        'get the tu from the file'
        return tu

    @classmethod
    def parse(cls):
        ...
        #call some inner functions
        #for example:
        translation_unit = cls.get_tu()

And the use from another module:

from cxxparser import CXXParser
cxxparser = CXXParser('Foo.c')
cxxparser.parse()

B. Use module-level functions, with globals:

#cxxparser.py
translation_unit = None
filename = ''

def get_tu(file):
    'get the tu from the file'
    return tu

def parse(filename='', cflags = None):
    global translation_unit
    global filename

    filename = filename
    if cflags:
         cflags = cflags
    ...
    #call some other functions
    translation_unit = get_tu(filename)

And the use from another module:

import cxxparser
cxxparser.parse('Foo.C')

P.S. - I tried to read all I can about it, and came across those questions - module-function-vs-staticmethod-vs-classmethod-vs-no-decorators-which-idiom-is?, python-class-design-staticmethod-vs-method, but even after reading bunch more of those - I'm still can't decide what the best approach in my case. Any help will be appreciated.

Lion answered 29/1, 2017 at 9:8 Comment(3)
You may want to post this on the softwareengineering.stackexchange.com. If you do, be sure to link the questions to each other.Farm
You may want to add alternative C: class with non-static methods. If you are going through the effort of using a class, you might as well allow multiple instances of the class. You may be surprised when you want to use two of them.Farm
Note: When you write filename = filename you're just assigning the same value to the same local variable it does not do what you expect it does.Byler
C
0

Using the global statement in a function to allow modifications to global variables is highly frowned upon in Python.

Since filename are cflags instance-specific attributes, it makes more sense to make the methods instance methods instead so that it would allow different parser instances to be instantiated for different files and/or different flags:

class CXXParser:
    def __init__(self, filename, cflags = None):
        super().__init__()
        self.filename = filename
        self.cflags = cflags
        self.translation_unit = None

    def get_tu(self):
        # get tu from self.filename
        ...
        return tu

    def parse(self):
        ...
        self.translation_unit = cls.get_tu()
Cartwright answered 2/1 at 8:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.