如何在Python中声明常量?
在Java中,我们做:
public static final String CONST_NAME = "Name";
如何在Python中声明常量?
在Java中,我们做:
public static final String CONST_NAME = "Name";
当前回答
编辑:添加了Python 3的示例代码
注意:另一个答案看起来提供了一个更完整的实现,类似于下面(具有更多的功能)。
首先,创建一个元类:
class MetaConst(type):
def __getattr__(cls, key):
return cls[key]
def __setattr__(cls, key, value):
raise TypeError
这可以防止静态属性被更改。然后创建另一个使用该元类的类:
class Const(object):
__metaclass__ = MetaConst
def __getattr__(self, name):
return self[name]
def __setattr__(self, name, value):
raise TypeError
或者,如果你使用的是python3:
class Const(object, metaclass=MetaConst):
def __getattr__(self, name):
return self[name]
def __setattr__(self, name, value):
raise TypeError
这应该可以防止实例道具被更改。要使用它,继承:
class MyConst(Const):
A = 1
B = 2
现在,直接或通过实例访问的props应该是常量:
MyConst.A
# 1
my_const = MyConst()
my_const.A
# 1
MyConst.A = 'changed'
# TypeError
my_const.A = 'changed'
# TypeError
下面是上面的一个例子。下面是Python 3的另一个例子。
其他回答
也许pconst库会帮助你(github)。
$ PIP安装pconst
from pconst import const
const.APPLE_PRICE = 100
const.APPLE_PRICE = 200
“APPLE_PRICE”的常量值不可编辑。
您可以使用namedtuple作为一种变通方法来有效地创建一个常量,其工作方式与Java中的静态final变量(Java“常量”)相同。作为一种变通方法,它是优雅的。(更优雅的方法是简单地改进Python语言——什么样的语言可以让您重新定义math.pi?——但我跑题了。)
(当我写这篇文章时,我意识到这个问题的另一个答案提到了namedtuple,但我将在这里继续,因为我将展示一种更接近于您在Java中所期望的语法,因为不需要像namedtuple那样创建命名类型。)
跟着你的例子,你会记得在Java中,我们必须在某个类中定义常量;因为你没有提到类名,我们称它为Foo。下面是Java类:
public class Foo {
public static final String CONST_NAME = "Name";
}
这里是等效的Python。
from collections import namedtuple
Foo = namedtuple('_Foo', 'CONST_NAME')('Name')
我想在这里补充的关键点是,您不需要单独的Foo类型(“匿名命名元组”会很好,尽管这听起来有点矛盾),所以我们将命名元组命名为_Foo,这样它就不会转义到导入模块中。
这里的第二点是,我们立即创建了nametuple的一个实例,称其为Foo;没有必要在单独的步骤中执行此操作(除非您想这样做)。现在你可以做你在Java中可以做的事情:
>>> Foo.CONST_NAME
'Name'
但你不能给它赋值:
>>> Foo.CONST_NAME = 'bar'
…
AttributeError: can't set attribute
确认:我认为我发明了命名元组方法,但后来我看到其他人给出了类似的答案(尽管不那么紧凑)。然后我还注意到Python中的“命名元组”是什么?,这就指出了sys。version_info现在是一个命名元组,所以可能Python标准库早就提出了这个想法。
注意,不幸的是(这仍然是Python),你可以完全删除整个Foo赋值:
>>> Foo = 'bar'
(facepalm)
但至少我们阻止了福星。CONST_NAME值,这比什么都没有好。祝你好运。
除了上面的两个答案(只使用大写的变量名,或者使用属性使值为只读),我想提到的是,可以使用元类来实现命名常量。我在GitHub提供了一个使用元类的非常简单的解决方案,如果你想让值的类型/名称更有信息,这可能会很有帮助:
>>> from named_constants import Constants
>>> class Colors(Constants):
... black = 0
... red = 1
... white = 15
...
>>> c = Colors.black
>>> c == 0
True
>>> c
Colors.black
>>> c.name()
'black'
>>> Colors(0) is c
True
这是稍微高级一些的Python,但仍然非常容易使用和方便。(该模块有更多的特性,包括常量是只读的,请参阅它的README。)
在各种存储库中也有类似的解决方案,但据我所知,它们要么缺乏我对常量所期望的基本特性之一(比如是常量,或者是任意类型),要么添加了一些深奥的特性,使它们不那么普遍适用。但是YMMV,我很感激你的反馈。: -)
这并不完全是常数,但从python 3.7开始,你可以使用如下所示的数据类模块:
from dataclasses import dataclass
from typing import Final
@dataclass(frozen=True)
class A():
a1:Final = 3
a = A()
a.a1 = 4
---------------------------------------------------------------------------
FrozenInstanceError Traceback (most recent call last)
<ipython-input-14-5f7f4efc5bf0> in <module>
----> 1 a.a1 = 4
<string> in __setattr__(self, name, value)
FrozenInstanceError: cannot assign to field 'a1'
属性是创建常量的一种方法。你可以通过声明一个getter属性来做到这一点,但忽略setter。例如:
class MyFinalProperty(object):
@property
def name(self):
return "John"
您可以看看我写的一篇文章,以找到更多使用Python属性的方法。