How do I create a constant in Python?

2018-12-31 23:08发布

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?

30条回答
笑指拈花
2楼-- · 2018-12-31 23:59

There's no perfect way to do this. As I understand it most programmers will just capitalize the identifier, so PI = 3.142 can be readily understood to be a constant.

On the otherhand, if you want something that actually acts like a constant, I'm not sure you'll find it. With anything you do there will always be some way of editing the "constant" so it won't really be a constant. Here's a very simple, dirty example:

def define(name, value):
  if (name + str(id(name))) not in globals():
    globals()[name + str(id(name))] = value

def constant(name):
  return globals()[name + str(id(name))]

define("PI",3.142)

print(constant("PI"))

This looks like it will make a PHP-style constant.

In reality all it takes for someone to change the value is this:

globals()["PI"+str(id("PI"))] = 3.1415

This is the same for all the other solutions you'll find on here - even the clever ones that make a class and redefine the set attribute method - there will always be a way around them. That's just how Python is.

My recommendation is to just avoid all the hassle and just capitalize your identifiers. It wouldn't really be a proper constant but then again nothing would.

查看更多
旧时光的记忆
3楼-- · 2019-01-01 00:01

Python dictionaries are mutable, so they don't seem like a good way to declare constants:

>>> constants = {"foo":1, "bar":2}
>>> print constants
{'foo': 1, 'bar': 2}
>>> constants["bar"] = 3
>>> print constants
{'foo': 1, 'bar': 3}
查看更多
看风景的人
4楼-- · 2019-01-01 00:06

Maybe pconst library will help you (github).

$ pip install pconst

from pconst import const
const.APPLE_PRICE = 100
const.APPLE_PRICE = 200

[Out] Constant value of "APPLE_PRICE" is not editable.

查看更多
后来的你喜欢了谁
5楼-- · 2019-01-01 00:10

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:

  1. 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.
  2. The setter function raises a TypeError so it's read-only
  3. 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.

  1. To define the identifier FOO, firs define two functions (fset, fget - the names are at my choice).
  2. Then use the built-in property function to construct an object that can be "set" or "get".
  3. Note hat the property function's first two parameters are named fset and fget.
  4. 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
查看更多
何处买醉
6楼-- · 2019-01-01 00:10

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 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 namedtuple 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
查看更多
看淡一切
7楼-- · 2019-01-01 00:10

Edit: Added sample code for Python 3

Note: this other answer looks like it provides a much more complete implementation similar to the following (with more features).

First, make a metaclass:

class MetaConst(type):
    def __getattr__(cls, key):
        return cls[key]

    def __setattr__(cls, key, value):
        raise TypeError

This prevents statics properties from being changed. Then make another class that uses that metaclass:

class Const(object):
    __metaclass__ = MetaConst

    def __getattr__(self, name):
        return self[name]

    def __setattr__(self, name, value):
        raise TypeError

Or, if you're using Python 3:

class Const(object, metaclass=MetaConst):
    def __getattr__(self, name):
        return self[name]

    def __setattr__(self, name, value):
        raise TypeError

This should prevent instance props from being changed. To use it, inherit:

class MyConst(Const):
    A = 1
    B = 2

Now the props, accessed directly or via an instance, should be constant:

MyConst.A
# 1
my_const = MyConst()
my_const.A
# 1

MyConst.A = 'changed'
# TypeError
my_const.A = 'changed'
# TypeError

Here's an example of above in action. Here's another example for Python 3.

查看更多
登录 后发表回答