1

我必须在 python 中编写一个以前用 Java 编写的库。来自 Java 背景的 python 给我带来了一些困难。我坚持选择正确的pythonic做事方式..

所以,我的java代码是这样的:

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);
    }
}

我想用python写一些东西。我理解两种语言完全不同。我不想复制确切的代码,但我想在 python 中编写一些东西,它可以提供 Java 代码提供的功能。

所以我想出了类似的东西:

# 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");

我想知道:

  1. 这是正确的pythonic方式吗?

  2. 我想将 ErrorEnum1,2,3,4 和常量移出 MyEnums 类作为模块变量。但是这样我就会在我的所有变量中有一个很长的列表。当我在其他模块中导入 Enums 模块时,我也有变量名冲突的风险(其他一些 Enums2 模块也可能有 ErrorEnum1,2,3.. 但这不是一个大问题。我们总是可以使用 Enums.ErrorEnum1 和 Enums2 .ErrorEnum1)。我想对了吗?

  3. 我知道这并不完美(我的第一个 python 代码)。所以我邀请你们给我一些想法。

谢谢

4

3 回答 3

5

好吧,我想你知道你的代码不是最优的,当然不是要走的路。另一个问题是我们不能说你怎么能“用python写一些东西给我Java代码提供的功能”,因为我们不知道你到底想做什么。也就是说,您的代码中有很多明显的 Java 偏见,可以毫无问题地删除:

  • 首先,为什么要有 aMyEnumBaseClass和 a MyEnumClass?你只能拥有一个。它将减少类的数量和模块的数量。即使你想扩展你的枚举,你会发现,在简化你的代码之后,你MyEnumClass会很简单,你可以毫无问题地扩展它。

  • 现在,请不要使用 getter 和 setter。你没有理由使用它们,因为你有属性。如果您的属性只会获取和设置值,请不要使用属性:

    class MyEnumClass(object):
        def __init__(self, value, description, ui = None):
            self.value = value
            self.description = description
    
  • 仅仅为了保存类似常量的值而创建一个类真的很丑陋,例如MyEnumClassConstantsand MyEnums。只需在模块级别创建一些变量。让我们在下面的项目之后看看如何做到这一点。

  • 另外,为什么是getEnum()类方法?这可能只是一个函数,您不必担心冲突,因为它位于模块内部:

    def getEnum(value, itr):
        for enumObj in itr:
            if enumObj.value == value:
                return enumObj
        return None
    
  • 如果您要设置一些带有序号的变量,您可能需要使用拆包习语

    (
        ERROR1,
        ERROR2,
        ERROR3,
        ERROR4
    ) = range(1, 5)
    
  • 这个成语也可以用来创建你的枚举列表:

    _enums = (
        ErrorEnum1,
        ErrorEnum2,
        ErrorEnum3,
        ErrorEnum4
    ) = (
        MyEnumClass(ERROR1, "ERROR1"),
        MyEnumClass(ERROR2, "ERROR2"),
        MyEnumClass(ERROR3, "ERROR3"),
        MyEnumClass(ERROR4, "ERROR4")
    )
    
  • 老实说,我很乐意_enums作为模块的公共成员离开,但让我们轻松处理您的 Java-itis :P 正如我们对 所做的那样getEnum(),让我们​​对其他类方法进行处理:将它们声明为模块中的函数:

    def getCount():
        return len(_enums)
    
    def getList():
        return _enums
    
  • 我们甚至可以getEnum()通过更改默认参数来改进:

    def getEnum(value, itr=_enums):
        for enumObj in itr:
            if enumObj.value == value:
                return enumObj
        return None
    
  • 我也很乐意在__all__这里禁止声明。唯一不属于接口的部分是元组,根据PEP-8_enums ,它前面是元组,这意味着它不应该在外部使用。但让我们说它会留下来。你的模块有一个新的接口,有更多的常量和函数:_

    __all__ = ["MyEnumClass", "ERROR1", "ERROR2", "ERROR3", "ERROR4",
            "ErrorEnum1", "ErrorEnum2", "ErrorEnum3", "ErrorEnum4",
            "getCount", "getList", "getEnum"]
    

    似乎MyEnumClass从界面中删除会更好,但是您可能想要使用它,所以我将离开它。请注意,该__all__也不会避免访问模块的其他组件。它只是更改了文档

最终结果将是这样的:

__all__ = ["MyEnumClass", "ERROR1", "ERROR2", "ERROR3", "ERROR4",
        "ErrorEnum1", "ErrorEnum2", "ErrorEnum3", "ErrorEnum4",
        "getCount", "getList", "getEnum"]

class MyEnumClass(object):
    def __init__(self, value, description, ui = None):
        self.value = value
        self.description = description

(
    ERROR1,
    ERROR2,
    ERROR3,
    ERROR4
) = range(1, 5)


_enums = (
    ErrorEnum1,
    ErrorEnum2,
    ErrorEnum3,
    ErrorEnum4
) = (
    MyEnumClass(ERROR1, "ERROR1"),
    MyEnumClass(ERROR2, "ERROR2"),
    MyEnumClass(ERROR3, "ERROR3"),
    MyEnumClass(ERROR4, "ERROR4")
)

def getCount():
    return len(_enums)

def getList():
    return _enums

def getEnum(value, itr=_enums):
    for enumObj in itr:
        if enumObj.value == value:
            return enumObj
    return None

(已编辑)这实际上并不简单。如果我要创建错误代码,我只会创建ERROR1ERROR2变量 - 没有类,没有函数,只有变量中的值。实际上,即使创建错误代码的想法似乎也不合适:您应该更喜欢创建异常,因为正如 Python 之禅所说,错误永远不应该默默地过去(或者,正如 Eric Raymond 的 Unix 哲学所说,当你必须失败时,大声失败并尽快)。尽管如此,我敢打赌,我所做的更改可以让您对编写 Python 有更准确的了解。

你可能会觉得这样做事很痒,但相信我,这是最好的方法。有些人可能在某些方面不同意我的观点,但这个想法是提出的。我主要是一名 Java 开发人员,但跟随语言的音乐起舞很重要——不要试图将外国概念强加于其中。

最后,一些重要的参考资料:

  • PEP-20 - Python 的禅宗:在 Python 和 Python 中开发的核心价值有点诗意的列表。
  • PEP-8 - Python 的风格指南。立即阅读。
  • Python 不是Java——关于避免在 Python 中使用不恰当的 Java 习惯的最佳指南之一。
于 2012-06-26T22:06:53.197 回答
0

一种更 Pythonic 的方法:

class EnumValue(object):
    def __init__(self, value, description):
        self.value = value
        self.description = description

class EnumType(object):
    @classmethod
    def lookup(cls, value):
        for error in cls.VALUES:
            if error.value == value:
                return value
        raise ValueError(value)    

class MyErrors(EnumType):
    ERROR1 = EnumValue(1, "Simple Errors")
    ERROR2 = EnumValue(2, "Bigger Errors")
    ERROR3 = EnumValue(3, "Really Big Errors")

    VALUES = [ERROR1, ERROR2, ERROR3]
于 2012-06-26T21:29:51.023 回答
0
  • 一般来说,Python 类属性是公开的,除非有充分的理由不公开。

  • 如果属性必须@property是私有的,那么使用装饰器比使用 getProperty 方法更符合 Pythonic 。

.

class MyEnumBaseClass(object):
    def __init__(self, value, description, ui=None):
        self.value = value
        self._description = description
        self.ui = [] if ui is None else ui

    @property
    def description(self):
        return self._description

    @classmethod
    def get_enum(cls, value, itr):
        for enumObj in itr:
            if enumObj.value == value:
                return enumObj
        return None
于 2012-06-26T20:56:15.497 回答