35

I am writing a program in python which contains many constant variables. I would like to create a file that will hold all these variables like the .h file in C that contains many #define. I tried to use configparser however I didn't find it easy and fun to use.

Do you know a better way?

1
  • As far as configuration variables go, you can set environment variables and read them from within your code. You could also use JSON or YAML files. Commented May 25, 2018 at 17:17

6 Answers 6

42

Constants (in a sense) in Python 3.8+

Python 3.8 introduces the typing.Final type qualifier, which is used to indicate that a variable or attribute should not be reassigned, redefined, or overridden.

PEP 591 -- Adding a final qualifier to typing

from typing import Final # Annotate module variables # (with or without an explicit type, using the syntax Final[<type>]) # (type is auto-determined in absence of an explicit type) PI: Final[float] = 3.141592654 ANSWER_TO_EVERYTHING: Final = 42 # Annotate instance variables in class bodies # (explicit type is needed if no value is assigned) class Point: x: Final[int] y: Final = 0 def __init__(self, x: int): self.x = x # Annotate instance variables directly # (only allowed in __init__ methods) class Person: def __init__(self, birth_year: int): self.birth_year: Final = birth_year 

Linters and type checkers will show you warnings if you reassign or redefine Final variables. Note that there is no runtime check, so you can still run the code below.

ANSWER_TO_EVERYTHING: Final = 42 ANSWER_TO_EVERYTHING = 420 # shows warning print(ANSWER_TO_EVERYTHING) # prints 420 

There is also the typing.final decorator, which is used to restrict inheriting classes and overriding methods.

Sign up to request clarification or add additional context in comments.

Comments

32

Python does not allow constant declarations like C or C++.

Normally in Python, constants are capitalized (PEP 8 standards) which helps the programmer know it's a constant.

Ex. MY_CONSTANT = "Whatever"

Another valid way of doing it which I don't use but heard of, is using a method:

def MY_CONSTANT(): return "Whatever" 

Now in theory, calling MY_CONSTANT() acts just like a constant.

EDIT

Like the comments says, someone can go and change the value by calling

MY_CONSTANT = lambda: 'Something else' 

but don't forget the same person can call MY_CONSTANT = "Something else" in the first example and change the initial value. In both cases it is unlikely but possible.

5 Comments

MY_CONSTANT = lambda: 'Something else' – Not sure why you'd bother with a "constant function", it's not any more constant.
@scharette The point is that whether you use def or lambda, you can still easily change the value of MY_CONSTANT; it's just a name that refers to some object, whether that object be an int or a function. Plus, the overhead of calling a function (both the lexical overhead of having to add () and the run-time overhead of setting up the stack frame) outweigh any perceived benefit.
MY_CONSTANT = lambda: "new value"! is just as easy to write as MY_CONSTANT = "new value!"; making it a function doesn't do anything useful.
You're right, this is not how I understood what he meant. I'm not trying to say this is a real constant, he's asking for C like constants, which doesn't exist in built-in python. My point is if someone is calling MY_CONSTANT = lambda: 'Something else' he really wants to change the value.
Samething goes for someone changing the constant itself in C. I mean a constant is a constant until the day someone goes around and change the inital value...
23

There are no constants in Python, the way they exist in C or Java. You can imitate them by functions:

def FOO(): return "foo" 

You can wrap the function call in a property, and thus make it look like a variable:

class Const: @property def FOO(self): return "foo" CONST = Const() # You need an instance if something == CONST.FOO: ... 

With a bit of meta stuff, one can get unsettable attributes with a terse syntax:

def const(cls): # Replace a class's attributes with properties, # and itself with an instance of its doppelganger. is_special = lambda name: (name.startswith("__") and name.endswith("__")) class_contents = {n: getattr(cls, n) for n in vars(cls) if not is_special(n)} def unbind(value): # Get the value out of the lexical closure. return lambda self: value propertified_contents = {name: property(unbind(value)) for (name, value) in class_contents.items()} receptor = type(cls.__name__, (object,), propertified_contents) return receptor() # Replace with an instance, so properties work. @const class Paths(object): home = "/home" null = "/dev/null" 

Now you can access Paths.home as a normal value, but can't assign to it. You can define several classes decorated with @const, as you might use several .h files.

Comments

9

You can use something like this:

Files structure:

myapp/ __init__.py settings.py main.py 

settings.py

CONST_A = 'A' CONST_B = 'B' 

__init__.py

from . import settings as global_settings class Settings: def __init__(self): for setting in dir(global_settings): if setting.isupper(): setattr(self, setting, getattr(global_settings, setting)) def __setattr__(self, attr, value): if not getattr(self, attr, None): super().__setattr__(attr, value) else: raise TypeError("'constant' does not support item assignment") settings = Settings() 

main.py

import settings print(settings.CONST_A) # prints A settings.CONST_A = 'C' # raises TypeError error print(settings.CONST_A) # prints A settings.CONST_C = 'C' # also able to add new constants print(settings.CONST_C) # prints C 

Overwritten __setattr__ in Settings class makes all the attributes read-only. The only requirement is to have all the constants in your settings.py written in capital letters. But be aware, that it's not gonna work if you import variables directly:

from settings import CONST_A print(settings.CONST_A) # prints A settings.CONST_A = 'C' # sets C print(settings.CONST_A) # prints C 

2 Comments

I taken your code as it, init Class giving me error 'indent expected'. After correcting, it's working. Cheers :-)
Interesting. import settings in main.py imports the variable settings not settings.py.
5

Just define a constants.py file and write all your constants. There is no other magic trick in Python. Use caps as a general convention.

1 Comment

Exactly. When in doubt look into Python standard library for inspiration.
1

Python isn't preprocessed. You can just create a file constant.py

#!/usr/bin/env python # encoding: utf-8 """ constant.py """ MY_CONSTANT = 50 

Import constant.py file when ever you want constant values like below example.

#!/usr/bin/env python # encoding: utf-8 """ example.py """ import constant print constant.MY_CONSTANT * 2 

This way you can use constants across project.

You also have the option, if the constants are tied to a particular class and used privately within that class of making them specific to that class:

class Foo(object): GOOD = 0 BAD = 1 def __init__(self... 

If you want to define and use entire module, making them on top of the module

PIE = 3.47 class Foo(object): def __init__(self... 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.