11

If I have python function with a string argument which needs to be in a specific list of values, what's the best way to handle this? Is there a convention to expressing this in the docstrings or anything?

eg.

def makeShape(shape):
   assert shape in ["circle", "square", "triangle"]

Is there a nicer way to express that shape should always be one of those three values?

ninhenzo64
  • 702
  • 1
  • 9
  • 23
  • If this function is part of a class, perhaps making that list a sort of class constant... Other than that, looks good to me. – Lix Mar 15 '14 at 00:37
  • Can you please clarify why you are using a string and what are your fundamental constraints? Could the enum idea suggested by @blue-ice be what you really need? – jrennie Mar 15 '14 at 00:58
  • Ok - maybe my example is a bit misleading as in that case you could create a class for each shape. My problem (this time - it seems to come up a lot though) is that I have an interface which runs in three modes: Load, Save and View. I want to pass a "mode" arg, but it can only be one of those three values. The Enum solution is very nice, but I'm on python2.6 unfortunately (in maya and nuke). – ninhenzo64 Mar 15 '14 at 18:25
  • 1
    @ninhenzo64 As noted in a comment on my answer, `enum`s have been backported to 2.6 through pypi. It should be do-able for you. – Blue Ice Mar 16 '14 at 00:31

4 Answers4

11

You could use an enum for the correct sort of shapes:

class rightShape(Enum):
    circle = 1
    square = 2
    triangle = 3

def makeShape(rightShape):
    # code in function

This will throw an honest-to-goodness error if you try to pass the function anything but a circle, square, or triangle.

Blue Ice
  • 7,888
  • 6
  • 32
  • 52
3

If this is a genuine error, you should raise an exception. I think TypeError would be a reasonable choice, but you may want to define your own.

assert statements are for development. Note that they are ignored when the -O argument is used, so they should not be relied upon to catch errors.

jrennie
  • 1,937
  • 12
  • 16
2

I personally also would prefer the enum solution, but I would like to highlight another, also very commonly used solution via typing's Literal:

from typing import Literal

PossibleShapes = Literal["circle", "square", "triangle"]

def makeShape(shape: PossibleShapes):
    ...
Michael Dorner
  • 17,587
  • 13
  • 87
  • 117
  • `makeShape(5)` will not throw an exception or show a warning. – 9769953 Aug 10 '23 at 13:15
  • Well, that has nothing to do with the solution discussed above. This is Python and it's dynamic typing: the type declaration is not enforced. Just search for "type hints" or see https://peps.python.org/pep-0484/ – Michael Dorner Aug 11 '23 at 06:53
0

Based on the answer of Blue Ice - thank you for the push to the enum direction.

As I stumbled over the same issue, this is my working example, also raising a type error.

    #!/usr/bin/python3

    from enum import Enum

    class InvalidParameters(Enum):
        ''' This is used to demonstrate the type error. '''
        ILLEGAL = 0

    class ValidParameters(Enum):
        ''' This is used to pass a valid parameter. '''
        LEGAL = 0

    def someFunc(param : ValidParameters) -> None:
        ''' Do some necessary stuff. '''
        if not type(param) is ValidParameters:
            raise TypeError('Parameter has to be of type ValidParameters')
        print(f'{ValidParameters(param)}')

    if __name__ == '__main__':
        ''' Some test cases, dis-/enable them one by one. '''
        someFunc('Wrong')
        #someFunc(InvalidParameters.ILLEGAL)
        #someFunc(ValidParameters.LEGAL)
        SystemExit(0)
Benny
  • 99
  • 9