如何在Python中声明常量?

在Java中,我们做:

public static final String CONST_NAME = "Name";

当前回答

我忍不住要提供我自己的极简元类实现(这可能是前面元类答案的变体)。

常量存储在容器类中(不需要实例化)。值只能设置一次,但设置后不能更改(或删除)。

就我个人而言,我目前还没有这个用例,但这是一个有趣的练习。

class MetaConstant(type):
    ''' Metaclass that allows underlying class to store constants at class-level (subclass instance not needed).
        Non-existent attributes of underlying class (constants) can be set initially, but cannot be changed or deleted.
    '''

    def __setattr__(klass, attr, value):
        'If attribute (constant) doesn\'t exist, set value. If attribute exists, raise AttributeError.'
        if hasattr(klass, attr):
            raise AttributeError(f'Can\'t change the value of the constant {klass.__name__}.{attr} to {value}'
                                 f' (the value of {klass.__name__}.{attr} is already set to'
                                 f' {getattr(klass, attr)}).')
        super().__setattr__(attr, value)

    def __delattr__(klass, attr):
        if hasattr(klass, attr):
            raise AttributeError(f'Can\'t delete constant {klass.__name__}.{attr}'
                                 f' (set to {getattr(klass, attr)}).')


class Constants(metaclass=MetaConstant):
    'Container class for constants. No instantiation required.'
    #pass               # uncomment if no constants set upon class creation
    B = 'Six'           # sets Constants.B to 'Six'


Constants.B = 6         # AttributeError
del Constants.B         # AttributeError

Constants.A = 'Five'    # sets Constants.A to 'Five'
Constants.A = 5         # AttributeError
del Constants.A         # AttributeError

请随意提出改进建议。

其他回答

在Python中,不能将变量或值声明为常量。


为了让程序员知道变量是常量,通常用大写:

CONST_NAME = "Name"

要在常量发生变化时引发异常,请参阅Alex Martelli的《Python中的常量》。注意,这在实践中并不常用。


从Python 3.8开始,有一个类型。最后一个变量注释,它将告诉静态类型检查器(如myypy)您的变量不应该被重新分配。这是最接近于Java的final。然而,它实际上并不能阻止重新分配:

from typing import Final

a: Final[int] = 1

# Executes fine, but mypy will report an error if you run mypy on this:
a = 2

你可以通过collections.namedtuple和itertools来实现:

import collections
import itertools
def Constants(Name, *Args, **Kwargs):
  t = collections.namedtuple(Name, itertools.chain(Args, Kwargs.keys()))
  return t(*itertools.chain(Args, Kwargs.values()))

>>> myConstants = Constants('MyConstants', 'One', 'Two', Three = 'Four')
>>> print myConstants.One
One
>>> print myConstants.Two
Two
>>> print myConstants.Three
Four
>>> myConstants.One = 'Two'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: can't set attribute

你可以使用Tuple常量变量:

tuple是一个有序且不可更改的集合

my_tuple = (1, "Hello", 3.4)
print(my_tuple[0])

我们可以创建一个描述符对象。

class Constant:
  def __init__(self,value=None):
    self.value = value
  def __get__(self,instance,owner):
    return self.value
  def __set__(self,instance,value):
    raise ValueError("You can't change a constant")

1)如果我们想在实例级使用常量,那么:

class A:
  NULL = Constant()
  NUM = Constant(0xFF)

class B:
  NAME = Constant('bar')
  LISTA = Constant([0,1,'INFINITY'])

>>> obj=A()
>>> print(obj.NUM)  #=> 255
>>> obj.NUM =100

Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ValueError: You can't change a constant

2)如果我们只想在类级别上创建常量,我们可以使用元类作为常量(描述符对象)的容器;所有下降的类将继承我们的常量(我们的描述符对象),没有任何可以修改的风险。

# metaclass of my class Foo
class FooMeta(type): pass

# class Foo
class Foo(metaclass=FooMeta): pass

# I create constants in my metaclass
FooMeta.NUM = Constant(0xff)
FooMeta.NAME = Constant('FOO')

>>> Foo.NUM   #=> 255
>>> Foo.NAME  #=> 'FOO'
>>> Foo.NUM = 0 #=> ValueError: You can't change a constant

如果我创建一个Foo的子类,这个类将继承常量,而不可能修改它们

class Bar(Foo): pass

>>> Bar.NUM  #=> 255
>>> Bar.NUM = 0  #=> ValueError: You can't change a constant

Python没有常量。

也许最简单的替代方法是为它定义一个函数:

def MY_CONSTANT():
    return 42

MY_CONSTANT()现在拥有常量的所有功能(加上一些讨厌的大括号)。