在枚举内定义一个类常量吗? [英] Is it possible to define a class constant inside an Enum?
问题描述
Python 3.4引入了新的模块 枚举
,它为该语言添加了枚举类型。 enum.Enum
的文档提供了一个示例< a>演示如何扩展:
>>>行星(枚举):
... MERCURY =(3.303e + 23,2.4397e6)
... VENUS =(4.869e + 24,6.0518e6)
... EARTH =(5.976e + 24,6.37814e6)
... MARS =(6.421e + 23,3.972e6)
... JUPITER =(1.9e + 27,7.1492e7)
... SATURN =(5.688e + 26,6.0268e7)
... URANUS =(8.686e + 25,2.5559e7)
... NEPTUNE =(1.024e + 26,2.4746e7)
... def __init __(self,mass,radius):
... self.mass = mass#in kilograms
... self.radius = radius#in meters
... @property
... def surface_gravity(self):
...#万能引力常数(m3 kg-1 s-2)
... G = 6.67300E -11
...返回G * self.mass /(self.radius * self.radius)
...
>>> Planet.EARTH.value
(5.976e + 24,6378140.0)
>>> Planet.EARTH.surface_gravity
9.802652743337129
此示例还演示了枚举
:在 surface_gravity()
属性方法中,定义了一个常量 G
这通常会在类级别定义,但是尝试在$ code>枚举中这样做只会将其添加为枚举的成员之一,因此它被定义在方法。
如果类想在其他方法中使用这个常量,那么它也必须在那里定义,这显然不是理想的。 >
有没有办法在枚举
中定义一个类常量,或者有一些解决方法来实现相同的效果?
这是高级行为,在创建的枚举的90%以内不需要。
根据文档:
允许的规则如下:名称(以单个下划线开头和结尾)由枚举保留,不能使用;
_sunder _
枚举中定义的所有其他属性将成为此枚举的成员,除了__ dunder __
名称和描述符
(方法也是描述符)
所以如果你想要一个类常量,你有几个选择:
- 在
__ init __
中创建 - 在类创建后添加
-
- 使用mixin
- 创建自己的
描述符
在 __ init __
中创建常量,并在类创建后添加它们都不会收集所有的类信息在一个地方。
适当时可以使用Mixins(请参阅dnozay的答案为了一个很好的例子),但是也可以通过建立一个基本的 Enum
类来实现这种情况,而实际的常量是内置的。
首先, e常量,将在下面的例子中使用:
class常量:#使用常量(对象)如果在Python 2
def __init __(self,value):
self.value = value
def __get __(self,* args):
return self.value
def __repr __(self)
返回'%s(%r)'%(self .__ class __.__ name__,self.value)
和一次性使用枚举示例:
从枚举导入枚举
class Planet (枚举):
MERCURY =(3.303e + 23,2.4397e6)
VENUS =(4.869e + 24,6.0518e6)
EARTH =(5.976e + 24,6.37814e6)
MARS =(6.421e + 23,39.72e6)
JUPITER =(1.9e + 27,7.1492e7)
SATURN =(5.688e + 26,6.0268e7)
URANUS = (8.686e + 25,2.5559e7)
NEPTUNE =(1.024e + 26,2.4746e7)
#万有引力常数
G =常数(6.67300E-11)
def __init __(self,mass,radius):
self.ma ss = mass#in kilograms
self.radius = radius#in meters
@property
def surface_gravity(self):
return self.G * self.mass /(self。半径* self.radius)
打印(行星.__ dict __ ['G'])#常数(6.673e-11)
打印(Planet.G)#6.673e-11
print(Planet.NEPTUNE.G)#6.673e-11
print(Planet.SATURN.surface_gravity)#10.44978014597121
最后,枚举导入枚举$ b $的多用枚举示例:
b
class AstronomicalObject(枚举):
#万能引力常数
G =常数(6.67300E-11)
def __init __(self,mass ,半径):
self.mass =质量
self.radius = radius
@property
def surface_gravity(self):
return self.G * self.mass /(self.radius * self.radius)
class Planet(AstronomicalObject):
MERCURY =(3.303e + 23,2.4397e6)
VENUS =(4.869e + 24,6.0518e6)
EARTH =(5.976e + 24,6.37814e6)
MARS =(6.421e +23,33972e6)
JUPITER =(1.9e + 27,7.1492e7)
SATURN =(5.688e + 26,6.0268e7)
URANUS =(8.686e + 25,2.5559e7 )
NEPTUNE =(1.024e + 26,2.4746e7)
类小行星(AstronomicalObject):
CERES =(9.4e + 20,4.75e + 5)
PALLAS =(2.068e + 20,2.72e + 5)
JUNOS =(2.82e + 19,2.2e + 5)
VESTA =(2.632e + 20,2.62e + 5
Planet.MERCURY.surface_gravity#3.7030267229659395
Asteroid.CERES.surface_gravity#0.27801085872576176
< hr>
注意:
常量
G
真的不是。可以将 G
重新绑定到其他东西:
Planet.G = 1
如果你真的需要它是不变的(也就是不可重新绑定),那么使用新的aenum库 [1],将阻止尝试重新分配常量
s以及枚举
成员。
[1 ] aenum
由作者 enum34
编写。
Python 3.4 introduces a new module enum
, which adds an enumerated type to the language. The documentation for enum.Enum
provides an example to demonstrate how it can be extended:
>>> class Planet(Enum):
... MERCURY = (3.303e+23, 2.4397e6)
... VENUS = (4.869e+24, 6.0518e6)
... EARTH = (5.976e+24, 6.37814e6)
... MARS = (6.421e+23, 3.3972e6)
... JUPITER = (1.9e+27, 7.1492e7)
... SATURN = (5.688e+26, 6.0268e7)
... URANUS = (8.686e+25, 2.5559e7)
... NEPTUNE = (1.024e+26, 2.4746e7)
... def __init__(self, mass, radius):
... self.mass = mass # in kilograms
... self.radius = radius # in meters
... @property
... def surface_gravity(self):
... # universal gravitational constant (m3 kg-1 s-2)
... G = 6.67300E-11
... return G * self.mass / (self.radius * self.radius)
...
>>> Planet.EARTH.value
(5.976e+24, 6378140.0)
>>> Planet.EARTH.surface_gravity
9.802652743337129
This example also demonstrates a problem with Enum
: in the surface_gravity()
property method, a constant G
is defined which would normally be defined at class level - but attempting to do so inside an Enum
would simply add it as one of the members of the enum, so instead it's been defined inside the method.
If the class wanted to use this constant in other methods, it'd have to be defined there as well, which obviously isn't ideal.
Is there any way to define a class constant inside an Enum
, or some workaround to achieve the same effect?
This is advanced behavior which will not be needed in 90+% of the enumerations created.
According to the docs:
The rules for what is allowed are as follows:
_sunder_
names (starting and ending with a single underscore) are reserved by enum and cannot be used; all other attributes defined within an enumeration will become members of this enumeration, with the exception of__dunder__
names anddescriptors
(methods are also descriptors).
So if you want a class constant you have several choices:
- create it in
__init__
- add it after the class has been created
- use a mixin
- create your own
descriptor
Creating the constant in __init__
and adding it after the class has been created both suffer from not having all the class info gathered in one place.
Mixins can certainly be used when appropriate (see dnozay's answer for a good example), but that case can also be simplified by having a base Enum
class with the actual constants built in.
First, the constant that will be used in the examples below:
class Constant: # use Constant(object) if in Python 2
def __init__(self, value):
self.value = value
def __get__(self, *args):
return self.value
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__, self.value)
And the single-use Enum example:
from enum import Enum
class Planet(Enum):
MERCURY = (3.303e+23, 2.4397e6)
VENUS = (4.869e+24, 6.0518e6)
EARTH = (5.976e+24, 6.37814e6)
MARS = (6.421e+23, 3.3972e6)
JUPITER = (1.9e+27, 7.1492e7)
SATURN = (5.688e+26, 6.0268e7)
URANUS = (8.686e+25, 2.5559e7)
NEPTUNE = (1.024e+26, 2.4746e7)
# universal gravitational constant
G = Constant(6.67300E-11)
def __init__(self, mass, radius):
self.mass = mass # in kilograms
self.radius = radius # in meters
@property
def surface_gravity(self):
return self.G * self.mass / (self.radius * self.radius)
print(Planet.__dict__['G']) # Constant(6.673e-11)
print(Planet.G) # 6.673e-11
print(Planet.NEPTUNE.G) # 6.673e-11
print(Planet.SATURN.surface_gravity) # 10.44978014597121
And, finally, the multi-use Enum example:
from enum import Enum
class AstronomicalObject(Enum):
# universal gravitational constant
G = Constant(6.67300E-11)
def __init__(self, mass, radius):
self.mass = mass
self.radius = radius
@property
def surface_gravity(self):
return self.G * self.mass / (self.radius * self.radius)
class Planet(AstronomicalObject):
MERCURY = (3.303e+23, 2.4397e6)
VENUS = (4.869e+24, 6.0518e6)
EARTH = (5.976e+24, 6.37814e6)
MARS = (6.421e+23, 3.3972e6)
JUPITER = (1.9e+27, 7.1492e7)
SATURN = (5.688e+26, 6.0268e7)
URANUS = (8.686e+25, 2.5559e7)
NEPTUNE = (1.024e+26, 2.4746e7)
class Asteroid(AstronomicalObject):
CERES = (9.4e+20 , 4.75e+5)
PALLAS = (2.068e+20, 2.72e+5)
JUNOS = (2.82e+19, 2.29e+5)
VESTA = (2.632e+20 ,2.62e+5
Planet.MERCURY.surface_gravity # 3.7030267229659395
Asteroid.CERES.surface_gravity # 0.27801085872576176
Note:
The Constant
G
really isn't. One could rebind G
to something else:
Planet.G = 1
If you really need it to be constant (aka not rebindable), then use the new aenum library [1] which will block attempts to reassign constant
s as well as Enum
members.
[1] aenum
is written by the author of enum34
.
这篇关于在枚举内定义一个类常量吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!