Query explained:
Is there a way to declare a constant in Python? In Java we can create constant values in this manner:
public static final String CONST_NAME = "Name";
What is the equivalent of the above Java constant declaration in Python?
How to create a constant in Python?
There’s no such way to create a “constant” in Python.
You cannot declare a variable or value as constant in Python. Just don’t change it.
If you are in a class, the equivalent would be:
class Foo(object):
CONST_NAME = "Name"
if not, it is just
CONST_NAME = "Name"
But you might want to have a look at the code snippet Constants in Python by Alex Martelli.
As of Python 3.8, there’s a typing.Final
variable annotation that will tell static type checkers (like mypy) that your variable shouldn’t be reassigned. This is the closest equivalent to Java’s final
. However, it does not actually prevent reassignment:
from typing import Final
a: Final = 1
# Executes fine, but mypy will report an error if you run mypy on this:
a = 2
Is there any const keyword in Python?
There’s no const
keyword as in other languages, however it is possible to create a Property that has a “getter function” to read the data, but no “setter function” to re-write the data. This essentially protects the identifier from being changed.
Here is an alternative implementation using class property:
Note that the code is far from easy for a reader wondering about constants. See explanation below
def constant(f):
def fset(self, value):
raise TypeError
def fget(self):
return f()
return property(fget, fset)
class _Const(object):
@constant
def FOO():
return 0xBAADFACE
@constant
def BAR():
return 0xDEADBEEF
CONST = _Const()
print CONST.FOO
##3131964110
CONST.FOO = 0
##Traceback (most recent call last):
## ...
## CONST.FOO = 0
##TypeError: None
Code Explanation:
- Define a function
constant
that takes an expression, and uses it to construct a “getter” – a function that solely returns the value of the expression. - The setter function raises a TypeError so it’s read-only
- Use the
constant
function we just created as a decoration to quickly define read-only properties.
And in some other more old-fashioned way:
(The code is quite tricky, more explanations below)
class _Const(object):
@apply
def FOO():
def fset(self, value):
raise TypeError
def fget(self):
return 0xBAADFACE
return property(**locals())
CONST = _Const()
print CONST.FOO
##3131964110
CONST.FOO = 0
##Traceback (most recent call last):
## ...
## CONST.FOO = 0
##TypeError: None
Note that the @apply decorator seems to be deprecated.
- To define the identifier FOO, firs define two functions (fset, fget – the names are at my choice).
- Then use the built-in
property
function to construct an object that can be “set” or “get”. - Note hat the
property
function’s first two parameters are namedfset
andfget
. - Use the fact that we chose these very names for our own getter & setter and create a keyword-dictionary using the ** (double asterisk) applied to all the local definitions of that scope to pass parameters to the
property
function
Is there a way to implement const in Python?
In Python instead of language enforcing something, people use naming conventions e.g __method
for private methods and using _method
for protected methods.
So in the same manner, you can simply declare the constant as all caps e.g.
MY_CONSTANT = "one"
If you want that this constant never changes, you can hook into attribute access and do tricks, but a simpler approach is to declare a function
def MY_CONSTANT():
return "one"
Only problem is everywhere you will have to do MY_CONSTANT(), but again MY_CONSTANT = "one"
is the correct way in python(usually).
You can also use named tuple to create constants:
>>> from collections import namedtuple
>>> Constants = namedtuple('Constants', ['pi', 'e'])
>>> constants = Constants(3.14, 2.718)
>>> constants.pi
3.14
>>> constants.pi = 3
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
Answer #3:
I’ve recently found a very succinct update to this which automatically raises meaningful error messages and prevents access via __dict__
:
class CONST(object):
__slots__ = ()
FOO = 1234
CONST = CONST()
# ----------
print(CONST.FOO) # 1234
CONST.FOO = 4321 # AttributeError: 'CONST' object attribute 'FOO' is read-only
CONST.__dict__['FOO'] = 4321 # AttributeError: 'CONST' object has no attribute '__dict__'
CONST.BAR = 5678 # AttributeError: 'CONST' object has no attribute 'BAR'
We define over ourselves as to make ourselves an instance and then use slots to ensure that no additional attributes can be added. This also removes the __dict__
access route. Of course, the whole object can still be redefined.
Edit – Original solution
I’m probably missing a trick here, but this seems to work for me:
class CONST(object):
FOO = 1234
def __setattr__(self, *_):
pass
CONST = CONST()
#----------
print CONST.FOO # 1234
CONST.FOO = 4321
CONST.BAR = 5678
print CONST.FOO # Still 1234!
print CONST.BAR # Oops AttributeError
Creating the instance allows the magic __setattr__
method to kick in and intercept attempts to set the FOO
variable. You could throw an exception here if you wanted to. Instantiating the instance over the class name prevents access directly via the class.
It’s a total pain for one value, but you could attach lots to your CONST
object. Having an upper class, class name also seems a bit grotty, but I think it’s quite succinct overall.
Summary:
Python doesn’t have constants.
Perhaps the easiest alternative is to define a function for it:
def MY_CONSTANT():
return 42
MY_CONSTANT()
now has all the functionality of a constant (plus some annoying braces).
Hope you learned something from this post.
Follow Programming Articles for more!