0

I have an async function that takes a single non optional parameter, that parameter can either be "all" (a string) or can be an integer. How do I handle it effectively without writing redundant code.

Here's a similar function:

async def myfunc(para):

I can process this later on easily like:

async def myfunc(para):
    try:
        int(para)
    except ValueError:
        if not para == "all":
            print("wrong parameter")

I know there's way to do this just with type hinting with using typing, I just don't know what

Note that the string can only be "all".

Do you know a better way to do this?

20
  • 1
    type hinting is just hinting for the function user to know what has to be put there, I don't think there is really another way to do this really (different approaches but not really shorter), depends on how that argument is used down the line tho Commented Aug 7, 2021 at 15:48
  • 1
    Note that type hinting won't actually apply this logic at runtime. But you're probably looking for Union[int, Literal["all"]]. Commented Aug 7, 2021 at 15:48
  • 3
    If myfunc is "basically" a function on integers, what does the exception "all" mean? There might be a better API design that sidesteps the issue altogether. Commented Aug 7, 2021 at 16:13
  • 2
    Better way: have a separate function which handles the "all" case, with no parameters. Commented Aug 7, 2021 at 16:25
  • 1
    @tdelaney Now the caller doesn't need to write the string "all" to call the function. If somebody else is giving the caller either an int or the string "all" and the caller is just passing it on, then yes, the problem should be moved further up. Otherwise you have a "stringly typed" program. Commented Aug 7, 2021 at 16:31

2 Answers 2

1
async def myfunc(para):
    if not(para == "all" or type(para)==int):
        print("Wrong parameter!")
        return

This only checks if the para input is valid, but does not do anything with it!!

async def myfunc(para):
    if para == "all":
        #Do "all" stuff
    elif type(para) == int:
        #Do int stuff
    else:
        print("Wrong parameter!")
        return

This might be a bit more useful

Sign up to request clarification or add additional context in comments.

3 Comments

" that parameter can either be "all" (a string) or can be an integer. " (emphasis mine). Passing an integer to your function results in AttributeError: 'int' object has no attribute 'isdigit'
Thank you for pointing this out if i just replaced para.isdigit() with type(para)==int
I like the answer except the second example. We don't know what OP plans to do next and should not assume that there are two different algorithms here.
0

A better way is to admit you have two different functions:

# myfunc(3)
async def myfunc1(x: int) -> X:
    ...

# myfunc("all")
async def myfunc2() -> X:
    ...

Now you don't have the problem of passing another string aside from "all", because you no longer have a function that accepts any string.


An aside

Since Python is a dynamically typed language, the rest of this answer will assume we are using code the successfully passes static type-checking; we assume that calls like myfunc1("not an int") are just as incorrect as myfunc2(3).)


There was never nothing special about the specific string "all"; you could have used "every" or "each" or "foo", and you would have structured the code the same way. The important thing was that "all" wasn't any other string: you really just wanted a single value that wasn't an int.

Taking the point further, why would you care if the caller passed any other string than "all"? Rather than raise an exception, you could just as easily have written

if para != "all":
    para = "all"

and proceeded.

None fills that role more cleanly: it's the only value of its type, so there's no possibility of passing an incorrect value. Now look at the following function:

async def myfunc2a(x: None) -> X:
    ...

There is only one legal way to call this function: myfunc2a(None). None isn't filling any semantic role here; it's there purely for syntactic reasons, because myfunc2a needs an argument. When that's the case, you might as well just eliminate the parameter altogether (which is legal in Python, unlike mathematical functions which are by definition mappings from an argument to a value).

 async def myfunc2b() -> X:
     ...

3 Comments

This answer is making a lot of assumptions about the author's design of this function. The question is How do I handle it effectively without writing redundant code. Implementing the same routine twice and forcing the caller to do the if seems like you are going in the opposite direction.
@tdelaney Read about inversion of control
I doubt there's very much redundant code if it has to handle arguments of two different types. What redundant code there is can likely be refactored into a single function that doesn't take arguments of different types.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.