I have to write a library in python which was written in Java before. Coming from a Java background python is giving me a little difficult time. I am stuck with choosing the right pythonic way of doing something..
So, My java code is something like:
import java.util.Collection;
public abstract class MyEnumBaseClass
{
protected int value;
protected String description = null;
protected MyEnumBaseClass(int iValue, String iDescription)
{
value = iValue;
description = iDescription;
}
public int getValue()
{
return value;
}
public String getDescription()
{
return description;
}
protected static MyEnumBaseClass getEnum(Collection<MyEnumBaseClass> iter, int value)
{
for (MyEnumBaseClass enumObj : iter)
{
if (enumObj.getValue() == value)
{
return enumObj;
}
}
return null;
}
}
import java.util.ArrayList;
import java.util.Collection;
public class MyEnumClass extends MyEnumBaseClass
{
private final static Collection<MyEnumBaseClass> enumList = new ArrayList<MyEnumBaseClass>();
public final static int ERROR1 = 1;
public final static int ERROR2 = 2;
public final static int ERROR3 = 3;
public final static int ERROR4 = 4;
public final static MyEnumClass ErrorEnum1 = new MyEnumClass(ERROR1, "ERROR1");
public final static MyEnumClass ErrorEnum2 = new MyEnumClass(ERROR2, "ERROR1");
public final static MyEnumClass ErrorEnum3 = new MyEnumClass(ERROR3, "ERROR1");
public final static MyEnumClass ErrorEnum4 = new MyEnumClass(ERROR4, "ERROR1");
protected MyEnumClass(int iValue, String iDescription)
{
super(iValue, iDescription);
}
public static int getCount()
{
return enumList.size();
}
public static Collection<MyEnumBaseClass> getList()
{
return enumList;
}
public static MyEnumBaseClass getEnum(int value)
{
return getEnum(enumList, value);
}
}
I want to write something this in python. I understand both languages are totally different. I don’t want to replicate exact code but I want to write something in python which give me the functionality Java code is giving.
So I came up with something like:
# MODULE MYENUMBASECLASS:::
class MyEnumBaseClass(object):
def __init__(self, iValue, iDescription, ui = None):
self._value = iValue
self._description = iDescription
def getValue(self):
return self._value
def getDescription(self):
return self._description
@classmethod
def getEnum(cls, value, itr):
for enumObj in itr:
if enumObj.getValue() == value:
return enumObj
return None
# MODULE: ENUMS:::
from MyEnumBaseClass import MyEnumBaseClass
__all__ = ["MyEnumClassConstants", "MyEnumClass", "MyEnums"]
_enumList = []
class MyEnumClassConstants(object):
ERROR1 = 1
ERROR2 = 2
ERROR3 = 3
ERROR4 = 4
class MyEnumClass(MyEnumBaseClass):
def __init__(self, v, d, ui):
global _enumList
super(MyEnumClass, self).__init__(v, d, ui)
_enumList.append(self)
@staticmethod
def getCount():
return len(_enumList)
@staticmethod
def getList():
return _enumList
@classmethod
def getEmum(cls, value, itr = None):
return super(MyEnumClass, cls).getEnum(value, _enumList)
class MyEnums(object):
ErrorEnum1 = MyEnumClass(MyEnumClassConstants.ERROR1, "ERROR1");
ErrorEnum2 = MyEnumClass(MyEnumClassConstants.ERROR2, "ERROR2");
ErrorEnum3 = MyEnumClass(MyEnumClassConstants.ERROR3, "ERROR3");
ErrorEnum4 = MyEnumClass(MyEnumClassConstants.ERROR4, "ERROR4");
I Want to know:
-
Is it the correct pythonic way of doing it?
-
I wanted to move the ErrorEnum1,2,3,4 and constants out of the MyEnums class as a module variable. But that way I will have a long list in my all variable. also I have a risk of variable name clash when I will import Enums module in other module (some other Enums2 module may also have ErrorEnum1,2,3.. But that is not a big problem. We can always use Enums.ErrorEnum1 and Enums2.ErrorEnum1). Am I thinking right?
-
I know this is not perfect (my first python code ever). So I invite you guys for giving me ideas.
Thanks
Well, I suppose you are aware that your code is less than optimal and certainly is not the way to go. Another problem is that we cannot say how you can “write something in python which give me the functionality Java code is giving” because we do not know exactly what you are trying to do. That said, there is a lot of obvious Java bias in your code that one can remove without any problem:
First, why to have a
MyEnumBaseClassand aMyEnumClass? You can have only one. It will reduce the number of classes and the number of modules. Even if you want to extend your enum, you will see that, after simplifying your code, yourMyEnumClasswill be so simple you can extend it without problems.Now, please, no getters and setters. You have no reason to use them, since you have properties. If your properties will only get and set values, do not use properties anyway:
It is really ugly to create a class just to hold constant-like values, such as
MyEnumClassConstantsandMyEnums. Just create some variables in the module level. Let us see how to do it just after the item below.Also, why is
getEnum()a classmethod? This can be a mere function and you have not to worry about conflicts because it is inside a module:If you are going to set some variables with sequential numbers, you may want to use the unpacking idiom:
This idiom can be used to create your list of enums, too:
To be honest, I would happily leave
_enumsas a public member of the module but let us take it easy with your Java-itis 😛 As we did withgetEnum(), let us do with the other classmethods: declare them as functions in the module:We can even improve the
getEnum()by changing the default parameter:I would also happily ban the
__all__declaration here. The only thing that is not part of the interface is the_enumstuple, and it is preceded by_which, according to PEP-8, means it should not be used externally. But let us say it will stay. Your module has a new interface, with more constants and functions:It seems it would be better to remove
MyEnumClassfrom the interface but well, you may want to use it so I will leave it. Note, also that the__all__value does not avoid the access to another components of the module. It just changes the documentationThe end result will be something like this:
(EDITED) This is really not much simpler. If I would create error codes, I would merely create the
ERROR1,ERROR2etc. variables – no classes, no functions, just values in variables. Actually, even the idea of creating error codes seems inappropriate: you should prefer to create exceptions since, as the Zen of Python states, errors should never pass silently (or, as the Eric Raymond’s Unix philosophy says, when you must fail, fail noisily and as soon as possible). Nonetheless, I bet the changes I’ve made can give you a more precise bit of taste of writing Python.You may feel itches about doing things this way, but believe me, it is the best way. Some people may disagree in some points with me but the idea is the one presented. I am mostly a Java developer, but it is important to dance to the music of the language – do not try to force foreign concepts into it.
Finally, some important references: