Is it possible to define a class constant inside an Enum?
This is advanced behavior which will not be needed in 90+% of the enumerations created.
According to the docs:
So if you want a class constant you have several choices: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).
- create it in
__init__
- add it after the class has been created
- use a mixin
- create your own
descriptor
__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 Disclosure: I am the author of the Python stdlib
Enum
, the enum34
backport, and the Advanced Enumeration (aenum
) library. How to define static constants in a Java enum?
As IntelliJ IDEA suggest when extracting constant - make static nested class. This approach works:
@RequiredArgsConstructor
public enum MyEnum {
BAR1(Constants.BAR_VALUE),
FOO("Foo"),
BAR2(Constants.BAR_VALUE),
...,
BARn(Constants.BAR_VALUE);
@Getter
private final String value;
private static class Constants {
public static final String BAR_VALUE = "BAR";
}
}
Declare constants inside of enum
I would use an enum
for the Categories
as well. If you place this in a top level class, it will look natural.
You have to define your enum
values before any other constants.
AFAIK This is done to simplify the syntax. You have the enum values first with a special, simplified syntax, followed by the constants you define. The need for this is more obvious when you start overriding methods in your constants.
Using Enum to store constants and use those constants in multiple classes
As commented, a constant that changes value is not a constant.
While you certainly can store changing state on an enum, you should ask yourself if doing so is a good idea. Generally not, in my opinion. Enum objects are usually used as constants, hence the convention of naming in all uppercase.
Map
You can accomplish the goal of having type-safe limited set of objects (enums) along with more obviously changing state by using a Map
. A map would pair each enum object with an object of a custom type to contain your changing state.EnumMap
The EnumMap
class is an implementation of Map
that is highly efficient, taking little memory and little CPU.
Here is some untested code as an example.
enum TravSalesAspect NODE_COUNT, SEQUENCE_LENGTH, POPULATION_SIZE, MAX_EDGE_WEIGHT, MUTATION_RATE ;
record AlgorithmState ( int val , boolean alreadySet ) {}
final Map< TravSalesAspect , AlgorithmState > map = new EnumMap<>() ;
Our map is empty. So we want to initialize with some default values.We access an array of all the enum objects. From that array, we make a stream. For each element in the stream, we put a key-value entry into the map.
Arrays.stream( TravSalesAspect.values() ).forEach( aspect -> map.put( aspect , new AlgorithmState( 0 , false ) ) ) ; // Initializing the map.
When you want to later set the state:if( ! map.get( someAspect ).alreadySet() )
{
map.put( someAspect , new AlgorithmState( 42 , true ) ) ;
}
By the way, note that in Java 16+ both enum
and record
can be defined locally if you so desire.Of course the code shown here is not thread-safe; beware.
Use final constant inside an enum
I suggest this :
enum KeyTypes {
BOLSA(), // default constructor
LLAVE(), // default constructor
MAGIC("net.labs.key.magical");
private static final String NONE = "";
private final String keyClass;
KeyTypes() {
this(NONE);
}
KeyTypes(String keyClass).....
}
Use Enum for keeping Constants
It is recommended to use Enum. The possible reasons are like
- provides default functions to iterate through constants
- Can write static functions to get the values based on key
Enum
Is an enum constant-specific class body static or non-static?
Well this is a strange case.
It appears that the problem is:
In this case, the private member should be accessible (6.6.1.):
Otherwise, the member or constructor is declared
private
, and access is permitted if and only if it occurs within the body of the top level class that encloses the declaration of the member or constructor.However, private members are not inherited (8.2):
Members of a class that are declared
private
are not inherited by subclasses of that class.Therefore,
printMe
is not a member of the anonymous subclass and the compiler searches for it within the superclass*Operation
(15.12.1):If there is an enclosing type declaration of which that method is a member, let T be the innermost such type declaration. The class or interface to search is T.
This search policy is called the "comb rule". It effectively looks for methods in a nested class's superclass hierarchy before looking for methods in an enclosing class and its superclass hierarchy.
And here is where it gets strange. Because
printMe
is found in a class that also enclosesPLUS
, the object that the method is called on is instead determined to be an enclosing instance ofOperation
, which doesn't exist (15.12.4.1):Otherwise, let T be the enclosing type declaration of which the method is a member, and let n be an integer such that T is the n'th lexically enclosing type declaration of the class whose declaration immediately contains the method invocation. The target reference is the n'th lexically enclosing instance of
this
.It is a compile-time error if the n'th lexically enclosing instance of
this
does not exist.
printMe
is only a member of Operation
(and not inherited), the compiler is compelled to invoke printMe
on a non-existent outer instance.However, the method is still accessible and we can find it by qualifying the invocation:
@Override
double apply(double x, double y) {
// now the superclass is searched
// but the target reference is definitely 'this'
// vvvvvv
super.printMe(x);
return x + y;
}
Yes, this is a confusing aspect of the language. On the one hand, an anonymous class is never static (15.9.5), on the other hand, an anonymous class expression can appear in a static context and therefore has no enclosing instance (8.1.3).The two error messages sound contradictory to each other [...].
An anonymous class is always an inner class; it is never
static
.
To help understand how this works, here is a formatted example:An instance of an inner class
I
whose declaration occurs in a static context has no lexically enclosing instances.
Everything in
class Example {
public static void main(String... args) {
new Object() {
int i;
void m() {}
};
}
}
italics
is the static context. The anonymous class derived from the expression in bold
is considered inner and non-static (but has no enclosing instance of Example
).Since the anonymous class is non-static it cannot declare static non-constant members, despite that it is itself declared within a static context.
* Besides obscuring the matter a little, the fact that
Operation
is an enum is completely irrelevant (8.9.1):The optional class body of an enum constant implicitly defines an anonymous class declaration that extends the immediately enclosing enum type. The class body is governed by the usual rules of anonymous classes [...].
Related Topics
Memory Error When Using Pandas Read_Csv
How to Modify Procfile to Run Gunicorn Process in a Non-Standard Folder on Heroku
Python: Give Start and End of Week Data from a Given Date
How to Read Class Attributes in the Same Order as Declared
How Do Threads Work in Python, and What Are Common Python-Threading Specific Pitfalls
Django: Adding "Nulls Last" to Query
Getting Gradient of Model Output W.R.T Weights Using Keras
Crontab Not Executing a Python Script
Python Insert Numpy Array into SQLite3 Database
How to Get a List of Keywords in Python
Create Spark Dataframe. Can Not Infer Schema for Type
How to Crop the Internal Area of a Contour
Conditional with Statement in Python
Make Part of a Matplotlib Title Bold and a Different Color
How to Ignore Hidden Files Using Os.Listdir()
What Do Backticks Mean to the Python Interpreter? Example: 'Num'