constants in Python: at the root of the module or in a namespace inside the module?

Python

Python Problem Overview


I'm building a Python module with about a hundred constants.

I would like to avoid naming issues when people import my module so I was wondering what would be the best way to do it.

MY_CONSTANT = 1
MY_SECOND_CONSTANT = 2
...
MY2_CONSTANT = "a"
MY2_SECOND_CONSTANT = "b"
...

Or

class My:
  CONSTANT = 1
  SECOND_CONSTANT = 2
  ...

class My2
  CONSTANT = "a"
  SECOND_CONSTANT = "b"
  ...

Or maybe another of your suggestions?

Coming from Java, I surely prefer the second way, but some might find it overkill...

Python Solutions


Solution 1 - Python

Well, it depends. Usually, constants are defined at module level. But if you have many constants for category_a and category_b, it might even make sense to add a subpackage constants with modules constants.category_a and constants.category_b.

I would refrain from using a class - it could be instanciated, which wouldn't make sense, and it has no advantage over a module apart from allowing you to cram more than one into one physical file (which you propably shouldn't if there are so many constants). The Java version would propably use a static class, but the Python equivalent is a module.

Name clashes aren't an issue in Python except when you import * - but you shouldn't do that anyway. As long as there are no name clashes inside the module, rest assured that the user will neither pull out all the names from your module into his own nor import it under a name that clashes with another module.

Solution 2 - Python

Every module provides its own namespace, so there's no need to create another one.

Having module foo.py:

FOO = 1
BAR = 2
SHMOO = 3
you may use it like this:
import foo
foo.BAR

Solution 3 - Python

From PEP 8 – Style Guide for Python Code:

> ### Constants > > Constants are usually defined on a module level and written in all capital letters with underscores separating words. Examples include MAX_OVERFLOW and TOTAL.

Solution 4 - Python

If you use classes you can forbid overwrite of constants (or forbid even adding constants to that class). Also advantage of using class over files(modules) is when you have many groups you need not to have many files.

So it would look like this:

class MyConstBaseClass: 
    """
    forbids to overwrite existing variables 
    forbids to add new values if "locked" variable exists
    """ 
    def __setattr__(self,name,value):
        if(self.__dict__.has_key("locked")):    
            raise NameError("Class is locked can not add any attributes (%s)"%name)
        if self.__dict__.has_key(name):
            raise NameError("Can't rebind const(%s)"%name)
        self.__dict__[name]=value

class MY_CONST_GRP1(MyConstBaseClass):
    def __init__(self):
        self.const1 = "g1c1"
        self.const2 = "g1c2"
my_const_grp1 = MY_CONST_GRP1()
        
class MY_CONST_GRP2(MyConstBaseClass):
    def __init__(self):
        self.const1 = "g2c1"
        self.const3 = "g2c3"
        self.locked = 1 # this will create lock for adding constants 
my_const_grp2 = MY_CONST_GRP2()

print my_const_grp1.const1 # prints "g1c1" 
print my_const_grp1.const2 # prints "g1c2"
print my_const_grp2.const1 # prints "g2c1"
print my_const_grp2.const3 # prints "g2c3"
my_const_grp1.new_constant = "new value" #adding constants is allowed to this group
#my_const_grp1.const1 = "new value" #redefine would raise an error
#my_const_grp2.new_constant = "first value" #adding constant is also forbidden
#my_const_grp2.const1 = "new value" #redefine would raise an error

Here is simillar example

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionOlivier GrégoireView Question on Stackoverflow
Solution 1 - Pythonuser395760View Answer on Stackoverflow
Solution 2 - PythonMichal ChruszczView Answer on Stackoverflow
Solution 3 - PythonSergey VedernikovView Answer on Stackoverflow
Solution 4 - PythonVit BernatikView Answer on Stackoverflow