我注意到现在很多库似乎更喜欢使用字符串而不是enum-type变量来表示参数。
以前人们会使用枚举,例如星期五的 dateutil.rrule.FR 似乎已经转向使用字符串(例如'FRI')。
相同的numpy(或pandas),其中搜索排序例如使用字符串(例如 side ='left',或 side ='对')而不是定义的枚举。为了避免疑问,在python 3.4之前,这可以很容易地实现为枚举:
class SIDE:
RIGHT = 0
LEFT = 1
enums-type变量的优点很明显:你不能在不引发错误的情况下拼错它们,它们为IDE提供了适当的支持等。
那么为什么要使用字符串,而不是坚持使用枚举类型?这不会使程序更容易出现用户错误吗?它不像枚举产生开销 - 如果有的话,它们应该稍微更高效。那么这种范式转变的时间和原因何时发生?
答案 0 :(得分:5)
我认为枚举更安全,特别是对于拥有多个开发人员的大型系统。
一旦需要改变这种枚举的价值,在许多地方查找和替换字符串并不是我的乐趣: - )
最重要的标准是恕我直言:用于模块甚至包中一个字符串似乎没问题,在公共API中我更喜欢枚举。
答案 1 :(得分:3)
[更新]
截至今日(2019年),Python引入了数据类 - 结合可选类型注释和静态类型分析器,如mypy,我认为这是一个已解决的问题。
至于效率,与大多数计算机语言相比,Python中的属性查找有点昂贵,所以我想有些库可能仍会出于性能原因选择避免使用它。
[原始答案]
恕我直言,这是一个品味问题。有些人喜欢这种风格:def searchsorted(a, v, side='left', sorter=None):
...
assert side in ('left', 'right'), "Invalid side '{}'".format(side)
...
numpy.searchsorted(a, v, side='right')
是的,如果您使用searchsorted
致电side='foo'
,您可能会在运行时获得AssertionError
方式 - 但至少可以很容易地看到该错误。
虽然其他人可能更喜欢(因为你强调的优势):
numpy.searchsorted(a, v, side=numpy.CONSTANTS.SIDE.RIGHT)
我赞成第一个因为我认为很少使用的常量不值得命名空间。您可能不同意,由于其他问题,人们可能会与任何一方保持一致。
如果你真的在乎,没有什么能阻止你定义你自己的“枚举”:
class SIDE(object):
RIGHT = 'right'
LEFT = 'left'
numpy.searchsorted(a, v, side=SIDE.RIGHT)
我认为这不值得,但这又是一种品味问题。
[更新]
斯蒂芬提出了一个公平的观点:一旦需要改变这种枚举的价值,在许多地方查找和替换字符串并不是我的乐趣: - )
我可以看到没有命名参数的语言会有多痛苦 - 使用您必须搜索字符串'right'
并获得大量误报的示例。在Python中,您可以缩小范围,搜索side='right'
。
当然,如果您正在处理已经有一组已定义的枚举/常量(如外部C库)的接口,那么肯定是模仿现有的约定。
答案 2 :(得分:1)
我更喜欢调试字符串。比较像
这样的对象side=1, opt_type=0, order_type=6
到
side='BUY', opt_type='PUT', order_type='FILL_OR_KILL'
我也喜欢" enums"值是字符串的地方:
class Side(object):
BUY = 'BUY'
SELL = 'SELL'
SHORT = 'SHORT'
答案 3 :(得分:1)
严格来说Python没有枚举 - 或者至少它没有在v3.4之前
https://docs.python.org/3/library/enum.html
我更愿意将您的示例视为程序员定义的常量。
在argparse
中,一组常量具有字符串值。虽然代码使用常量名称,但用户更经常使用字符串。
e.g. argparse.ZERO_OR_MORE = '*'
arg.parse.OPTIONAL = '?'
numpy
是较旧的第三方软件包之一(至少它的根源是numeric
)。字符串值比枚举更常见。事实上,我无法想到任何枚举(如你所定义的那样)。
答案 4 :(得分:1)
我知道这个问题已经得到回答,但是有一点根本没有解决:使用Enums存储的值时,必须显式调用Python Enum对象的值这一事实。
>>> class Test(Enum):
... WORD='word'
... ANOTHER='another'
...
>>> str(Test.WORD.value)
'word'
>>> str(Test.WORD)
'Test.WORD'
解决此问题的一种简单方法是提供__str__()
>>> class Test(Enum):
... WORD='word'
... ANOTHER='another'
... def __str__(self):
... return self.value
...
>>> Test.WORD
<Test.WORD: 'word'>
>>> str(Test.WORD)
'word'
是的,添加.value
并不是什么大问题,但这仍然很麻烦。使用常规字符串需要零额外的精力,无需额外的类或重新定义任何默认类方法。不过,在许多情况下,简单的str
不会出现问题,必须显式转换为字符串值。