admin管理员组

文章数量:1122832

I want to create a module called 'constants.py' that contain all the constants specific to my system.

To offer flexibility I would like to be able to access the constants directly like this:

constants.power_1
constants.power_2
constants.data_rate_1
constants.data_rate_2
...

because it is short, or access the constants through a dictionary like this:

constants['system_1']['power']
constants['system_2']['power']
constants['system_1']['data_rate']
constants['system_2']['data_rate']
...

because it is useful when sometimes I use a constant inside a loop like this:

systems = ['system_1', 'system_2']
for system in systems:
    power = constants[system]['power']
    var_2 = var_1 * power

My problem is that I cannot use both methods at the same time.

What I can do:

Option 1. Forget about accessing a constant like constants.power_1, and have only a dictionary like constants['power_1']. So I declare them like this in 'constants.py':

constants['power_1'] = 10
constants['system_1']['power'] = constants['power_1']

and use them like this:

from constants import *
var_2 = var_1 * constants['power_1']
var_2 = var_1 * constants['system_1']['power']

Cons:

  • I don't really like the import *, even if I import only one dictionary, I prefer a simple import.
  • The direct access is 4 characters longer (['']).

Option 2. Use an intermediate name for my dictionary. So I declare them like this in 'constants.py':

power_1 = 10
varname['system 1']['power'] = power_1

and use them like this:

import constants
var_2 = var_1 * constants.power_1
var_2 = var_1 * constants.varname['system 1']['power']

Cons:

  • I don't find a meaningful name for varname, because it is not necessary (I could put system, but it is redundant).
  • The long access gets longer.

Do you see another way to solve this?

I want to create a module called 'constants.py' that contain all the constants specific to my system.

To offer flexibility I would like to be able to access the constants directly like this:

constants.power_1
constants.power_2
constants.data_rate_1
constants.data_rate_2
...

because it is short, or access the constants through a dictionary like this:

constants['system_1']['power']
constants['system_2']['power']
constants['system_1']['data_rate']
constants['system_2']['data_rate']
...

because it is useful when sometimes I use a constant inside a loop like this:

systems = ['system_1', 'system_2']
for system in systems:
    power = constants[system]['power']
    var_2 = var_1 * power

My problem is that I cannot use both methods at the same time.

What I can do:

Option 1. Forget about accessing a constant like constants.power_1, and have only a dictionary like constants['power_1']. So I declare them like this in 'constants.py':

constants['power_1'] = 10
constants['system_1']['power'] = constants['power_1']

and use them like this:

from constants import *
var_2 = var_1 * constants['power_1']
var_2 = var_1 * constants['system_1']['power']

Cons:

  • I don't really like the import *, even if I import only one dictionary, I prefer a simple import.
  • The direct access is 4 characters longer (['']).

Option 2. Use an intermediate name for my dictionary. So I declare them like this in 'constants.py':

power_1 = 10
varname['system 1']['power'] = power_1

and use them like this:

import constants
var_2 = var_1 * constants.power_1
var_2 = var_1 * constants.varname['system 1']['power']

Cons:

  • I don't find a meaningful name for varname, because it is not necessary (I could put system, but it is redundant).
  • The long access gets longer.

Do you see another way to solve this?

Share Improve this question asked Nov 22, 2024 at 4:58 JamesJames 632 silver badges6 bronze badges 4
  • 1 "To offer flexibility I would like to be able to access the constants directly like this" - what kind of 'flexibility'? What's not flexible about just using the dictionary? If all you're doing is trying to save someone a few characters of typing, please stop - you're wasting your time and the result will be bad code. – Grismar Commented Nov 22, 2024 at 5:02
  • 1 If you insist on have both types of access, you could define a class that allows you access to the constant value defined as named variables (note that there's no such thing as a constant, you can name your variable in capitals to indicate its intended use as such). But also keep in mind that you could also write a class that actually functions as a container of constants that can't be changed directly, and functions just like a dictionary, which may be closer to what you really want. – Grismar Commented Nov 22, 2024 at 5:07
  • 1 Normally you create constants in classes or enums. As they provide autocomplete. – Albin Paul Commented Nov 22, 2024 at 5:11
  • use getattr to access your "dotted" object properties in a loop – folen gateis Commented Nov 22, 2024 at 6:52
Add a comment  | 

1 Answer 1

Reset to default 1

To be honest, if you wanted to do this I would recommend creating a class-based structure, that will provide a dictionary-like structure for hierarchical constants, and a flat namespace for individual constants.

Constants.py could look something like

class Constants:
def __init__(self):
    # flat - you can also maybe load this from a JSON so you don't touch this often
    self._flat_constants = {
        "power_1": 10,
        "power_2": 20,
        "data_rate_1": 100,
        "data_rate_2": 200,
    }
    
    # heirachy
    self._nested_constants = {
        "system_1": {
            "power": self._flat_constants["power_1"],
            "data_rate": self._flat_constants["data_rate_1"],
        },
        "system_2": {
            "power": self._flat_constants["power_2"],
            "data_rate": self._flat_constants["data_rate_2"],
        },
    }

def __getitem__(self, key):
    # First look through the flat ones
    if key in self._flat_constants:
        return self._flat_constants[key]
    
    # Then check nested ones
    if key in self._nested_constants:
        return self._nested_constants[key]
    
    raise KeyError(f"Constant '{key}' not found.")

def __getattr__(self, name):
    # Allow direct access to flat constants
    if name in self._flat_constants:
        return self._flat_constants[name]
    
    raise AttributeError(f"'Constants' object has no attribute '{name}'")

Then you can just use it by initializing wherever you plan to, knowing that you can use the dot to access the flat constants (constants.power_1), and the ['system_1]['power'] to access the nested ones.

Tip: If you eventually decide to load from a JSON, you should add some logic to raise an exception if duplicates are found in the keys (duplicates are allowed in JSON).

本文标签: pythonHow to create a module of constants accessible directly and through a dictionaryStack Overflow