Enum vs String as a parameter in a function

I noticed that many libraries now seem to prefer using strings over enum type variables for parameters.

If people previously used listings, for example. dateutil.rrule.FR on Friday, it looks like it is biased towards using a string (like "FRI" ).

Same thing in numpy (or pandas, for that matter), where searchsorted , for example, uses strings (e.g. side = 'left' or side = 'right' ) instead of a specific enumeration. For the avoidance of doubt, before python 3.4 this could easily be implemented as an enumeration as such:

class SIDE: RIGHT = 0 LEFT = 1 

And the advantages of an enum type variable are clear: you cannot skip them without causing errors, they offer the correct support for the IDE, etc.

So why use strings at all and not stick to enumeration types? Doesn't that make programs more prone to user errors? This is not like transfers that create overheads - if something should be a little more efficient. So, when and why did this paradigm shift?

+13
python coding-style numpy
source share
5 answers

[Update]

To date (2019), Python has introduced data classes - combined with optional type annotations and static type parsers like mypy, I think this is a resolved problem.

In terms of performance, searching for attributes in Python is a bit more expensive than most computer languages, so I guess some libraries decided to avoid it for performance reasons.

[original answer]

IMHO this is a matter of taste. Some people like this style:

 def searchsorted(a, v, side='left', sorter=None): ... assert side in ('left', 'right'), "Invalid side '{}'".format(side) ... numpy.searchsorted(a, v, side='right') 

Yes, if you call searchsorted with side='foo' , you can get the AssertionError method later at runtime - but at least the error will be pretty easy to spot when viewing the trace.

While other people may prefer (for the benefits that you highlighted):

 numpy.searchsorted(a, v, side=numpy.CONSTANTS.SIDE.RIGHT) 

I prefer the former because I think that rarely used constants are not worth the confusion of the namespace. You may not agree, and people may join either side due to other problems.

If you really don't care, nothing stops you from defining your own "enumerations":

 class SIDE(object): RIGHT = 'right' LEFT = 'left' numpy.searchsorted(a, v, side=SIDE.RIGHT) 

I think it is not worth it, but again it is a matter of taste.

[Update]

Stefan made a fair remark:

As soon as it becomes necessary to change the meaning of such an enumeration, finding and replacing a string in many places is not my idea of ​​fun :-)

I see how painful it can be in a language without named parameters - for example, you should find the string 'right' and get a lot of false positives. In Python, you can narrow your search to side='right' .

Of course, if you are dealing with an interface that already has a specific set of enumerations / constants (for example, an external C library), then yes, imitate existing conventions in all respects.

+4
source share

I think enumerations are safer, especially for larger systems with multiple developers.

As soon as it becomes necessary to change the meaning of such an enumeration, finding and replacing a string in many places is not my idea of ​​fun :-)

The most important IMHO criteria are usage: for use in a module or even a package, the string seems fine, in the public API I prefer enumerations.

+6
source share

I prefer lines for debugging. compare object like

 side=1, opt_type=0, order_type=6 

to

 side='BUY', opt_type='PUT', order_type='FILL_OR_KILL' 

I also like "enumerations", where the values ​​are strings:

 class Side(object): BUY = 'BUY' SELL = 'SELL' SHORT = 'SHORT' 
+1
source share

Strictly speaking, Python has no enumerations - or at least it wasn't before v3.4

https://docs.python.org/3/library/enum.html

I prefer to think of your example as programmable constants.

In argparse one set of constants has string values. Although the code uses constant names, users often use strings.

  eg argparse.ZERO_OR_MORE = '*' arg.parse.OPTIONAL = '?' 

numpy is one of the older third-party packages (at least its roots, such as numeric ). String values ​​are more common than enumerations. In fact, I can not escape from any enumerations (as you define them).

+1
source share

I understand that this question has already been answered, but there is one thing that has not been considered at all: the fact that Python Enum objects must be explicitly called for their value when using the values ​​stored in Enums.

 >>> class Test(Enum): ... WORD='word' ... ANOTHER='another' ... >>> str(Test.WORD.value) 'word' >>> str(Test.WORD) 'Test.WORD' 

One simple solution to this problem is to offer __str__()

 >>> class Test(Enum): ... WORD='word' ... ANOTHER='another' ... def __str__(self): ... return self.value ... >>> Test.WORD <Test.WORD: 'word'> >>> str(Test.WORD) 'word' 

Yes, adding .value not that difficult, but it's a nuisance nonetheless. Using regular strings requires zero extra effort, no extra classes, or overriding any class methods by default. However, in many cases there must be an explicit cast to a string value, where a simple str will not have a problem.

0
source share

All Articles