Here are the basic ideas (orientation: C++):
- You are responsible to find names for constants and this code provides a way to give values which differ from each other
- The context is to allow different enums with values starting by 0
- If you like to use constants like here: "Orientation.TOP" then place those constants in the relating class
- You still can assign your own values
About the code:
- It's not much code also it might look like (implementation + documentation + unittests)
- The __docformat__ is for epydoc. Temporarily remove the "@singleton" when trying to generate the HTML documentation (can not yet be handled by epydoc).
Example(s): Have a look at the unittests please.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | """
@author Thomas Lehmann
@file enum.py
@note The singleton example is taken from:
http://www.python.org/dev/peps/pep-0318/#examples
@note I don't use TAB's and indentation is 4.
@note epydoc wrongly interprets the class as a function.
Probably because of the decorator (without it works).
"""
__docformat__ = "javadoc en"
import inspect
import unittest
def singleton(theClass):
""" decorator for a class to make a singleton out of it """
classInstances = {}
def getInstance():
""" creating or just return the one and only class instance """
if theClass not in classInstances:
classInstances[theClass] = theClass()
return classInstances[theClass]
return getInstance
@singleton
class Enum(object):
""" class for providing enum functionality. An enum in C++ usually looks
like this: enum { A, B, C }; and the results are 0, 1 and 2 for A, B and C.
We provide similar functionality means auto incrementing of values for constants
added to an enum...
>>> TOP = enum("direction") # or enum(Direction) when Direction is a class
>>> LEFT = enum("direction") # or enum(Direction) when Direction is a class
>>> RIGHT = enum("direction") # or enum(Direction) when Direction is a class
>>> BOTTOM = enum("direction") # or enum(Direction) when Direction is a class
>>> assert TOP < LEFT < RIGHT < BOTTOM
<ul>
<li>You still can assign an individual value.
<li>You can place constants inside the class (if you like) -> Direction.TOP
<li>Same to C++: you have to pay attention where new constants are added. When
you insert it inbetween then you will 'move' the other values.
</ul>
"""
def __init__(self):
""" registered enums """
self.contexts = {}
def getNextId(self, context):
""" providing next id >= 0 on each call per context
@param context is a string
@return is an integer value being unique for given context
"""
if not context in self.contexts:
self.contexts[context] = -1
self.contexts[context] += 1
return self.contexts[context]
def enum(context):
""" wrapper for calling the singleton. Documentation is placed
at the class Enum.
@param context can be a string or a class
@return is an integer value being unique for given context
"""
if inspect.isclass(context):
return Enum().getNextId(context.__name__)
return Enum().getNextId(context)
class EnumTestCase(unittest.TestCase):
""" testing of class Enum """
def testSingleton(self):
""" testing the singleton mechanism """
instanceA = Enum()
instanceB = Enum()
self.assertEqual(instanceA, instanceB)
def testGetNextId(self):
""" example of creating two constants """
instance = Enum()
HORIZONTAL = instance.getNextId("orientation")
VERTICAL = instance.getNextId("orientation")
self.assertTrue(HORIZONTAL < VERTICAL)
def testEnumFunctionWithStringContext(self):
""" example of creating four constants with string as context """
class Direction:
TOP = enum("direction")
LEFT = enum("direction")
RIGHT = enum("direction")
BOTTOM = enum("direction")
self.assertTrue(Direction.TOP < Direction.LEFT < Direction.RIGHT < Direction.BOTTOM)
def testEnumFunctionWithClassContext(self):
""" example of creating four constants with a class as context
@note I have tried to move the enum code to the class but this
seems not to work """
class Vector:
def __init__(self):
self.vector = [0, 0]
X = enum(Vector)
Y = enum(Vector)
self.assertTrue(X < Y)
self.assertEqual(X, 0)
self.assertEqual(Y, 1)
if __name__ == "__main__":
suite = unittest.TestLoader().loadTestsFromTestCase(EnumTestCase)
unittest.TextTestRunner(verbosity=3).run(suite)
|
In "testEnumFunctionWithClassContext" I have tried to move the enum code to the class but this didn't work. Obviously is the class not fully defined yet:
class Vector:
X = enum(Vector)
Y = enum(Vector)
def __init__(self):
self.vector = [0, 0]
If you have an idea how this can be done, then please tell me.
Tags: enum
You can also use something as simple as a small function, Thomas:
With something so small, you can then do this in the interpreter: