I've got the following function, which given a string of the form 'a-02/b-03/foobarbaz_c-04'
, will extract the digits after a, b and c. The issue is that, for my use case, the input strings may not contain c, such that there will be no digits to extract.
Here's the code:
from typing import Tuple, Optional
def regex_a_b_c(name: str) -> Tuple[int, int, Optional[int]]:
a_b_info = re.search('a-(\d\d)/b-(\d\d)/', name)
a, b = [int(a_b_info.group(x)) for x in range(1, 3)]
c_info = re.search('c-(\d\d)', name)
if c_info:
c = int(c_info.group(1))
else:
c = None
return a, b, c
The issue I have is that, despite trying to make it clear that the last return argument is an Optional[int]
, I can't get my linter to stop complaining about the variable c.
I get a warning at the line c = None
that says:
Incompatible types in assignment (expression has type None, variable has type int)
How can I solve the issue?
If you don't annotate a variable, mypy will infer its type based on the very first assignment it sees.
So in this case, the line c = int(_info.group(1))
appears first, so mypy decides that the type must be int
. It then subsequently complains when it sees c = None
.
One way of working around this limitation is to just forward-declare the variable with the expected type. If you are using Python 3.6+ and can use variable annotations, you can do so like this:
c: Optional[int]
if c_info:
c = int(c_info.group(1))
else:
c = None
Or perhaps more concisely, like this:
c: Optional[int] = None
if c_info:
c = int(c_info.group(1))
If you need to support older versions of Python, you can annotate the type using the comment-based syntax, like so:
c = None # type: Optional[int]
if c_info:
c = int(c_info.group(1))
rje's suggestion of doing:
if c_info:
c = int(c_info.group(1))
return a, b, c
else:
return a, b, None
...is also a reasonable one.
Aside from the nice approach given by this answer, I came across another way to get mypy to ignore the line by adding comment like the following:
c = None # type: ignore
This seems to ignore the type for the current line, but does not effect the type inference for the other areas where the variable is used.
You should return either a tuple a,b,c
or a tuple a,b
without including c. This way you do not need to assign a value of None to c at all.
if c_info:
c = int(c_info.group(1))
return a, b, c
else:
return a, b
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With