-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
mypy can't infer type for functools.reduce #4673
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I believe there's a bug related to |
I don't think it's entirely due to Here are lines 37 through 49 ... you can see that both methods generate error messages, although they messages are different.
Here are the error messages:
|
For reference, here's the full example (I deleted code from the end that seems immaterial to mypy): import functools
from typing import List, Sequence
class B:
def __init__(self, x_list: Sequence['B']) -> None:
self.x_list = x_list
def __repr__(self) -> str:
return '{}([{}])'.format(self.__class__.__name__, ', '.join(
repr(x) for x in self.x_list))
class B1(B):
def __init__(self, v: str) -> None:
self.v = v
def __repr__(self) -> str:
return '{}({})'.format(self.__class__.__name__, repr(self.v))
class C:
def __init__(self, f_list: Sequence['C']) -> None:
self.f_list = f_list
def __repr__(self) -> str:
return '{}([{}])'.format(self.__class__.__name__, ', '.join(
repr(f) for f in self.f_list))
def m(self) -> B:
result = [] # type: List[B]
for item in self.f_list:
result += [item.m()]
return B(result)
def m_bad1(self) -> B:
result = functools.reduce(lambda result, item: result + [item.m()], # Error here
self.f_list, [])
return B(result)
def m_bad2(self) -> B:
result = functools.reduce(_combine, self.f_list, []) # Error here
return B(result)
def _combine(result: List[B], item: C) -> List[B]:
# See https://github.com/python/mypy/issues/4226
return result + [item.m()] |
Hm, actually both errors go away when I replace the init = [] # type: List[B] |
I could also make the error go away by adding |
Can you find a more minimal example that doesn't depend on the builtin reduce? I've got a feeling it's got to do with Sequence vs. List and a generic Callable. |
This feels like it's related to needing the var annotation on
|
I tried making my own version of
and then changing the |
This seems to be a simpler example (I removed the
Which causes this message:
|
What if you write your own In any case it's clear that you've hit upon a case where the type solver gets its knickers in a knot. That's really old code and probably only |
Writing my own
Here's the full code (line 10 is marked with a comment):
|
The problem on line 10 in your last example is because Looking back, the same is the case in the previous example. These two errors look justified to me. But the original error is more complicated, and here's a repro: from typing import *
T = TypeVar('T')
S = TypeVar('S')
def reduce(func: Callable[[T, S], T], seq: Iterable[S], init: T) -> T: ...
def combine(res: List[str], item: int) -> List[str]: ...
def error(items: Sequence[int]) -> None:
result = reduce(combine, items, []) # <-- errors here The errors are closer to your original:
|
I can also get this error (unless I've made another mistake with type annotations):
with this source: from typing import *
_S = TypeVar('_S')
_T = TypeVar('_T')
def my_reduce(sequence: List[_S], initial: _T) -> _T:
# def my_reduce(sequence: List[int], initial: List[str]) -> List[str]:
result = initial
for item in sequence:
result = _combine(result, item) # <==== Line 10
return result
def _combine(result: List[_T], item: _S) -> List[_T]:
# def _combine(result: List[str], item: int) -> List[str]:
# return result + [str(item)]
return result |
Is this a correct summary? -- mypy has a bug(s) that's exposed by the code examples in this thread, and @JukkaL might eventually dig into the grungy old code and figure out the problem. |
Yes. |
Can this be marked as a bug, please? (I don't seem to have the authority to add a label) |
Hi team! this is the signature of me def _generate(source: _RecursiveDict, destination: _RecursiveDictMap, mapping: AttrMapping) -> _RecursiveDictMap: And here is the place where I'm having problems(where it says return dict(
reduce(function=lambda destination, mapping: DictMapper._generate(source=source,
destination=destination, # type: ignore
mapping=mapping),
sequence=self._mappings,
initial=_RecursiveDictMap())
) Thx! |
I still have this issue. MWE
returns
|
Still present in mypy 1.8.0 |
Uh oh!
There was an error while loading. Please reload this page.
The attached program has three methods (
C.m
,C.m_bad1
,C.m_bad2
) that compute the same value; only one of them is accepted by mypy (and by sheer coincidence,C.m
is the style that Guido prefers and the others are a style he doesn't). I looked at the typeshed definition offunctools.reduce
,and it appears to be correct.Issue 4226 suggests that the
lambda
might be the problem; but that seems to only shift the problem (C.m_bad
1 uses alambda
andC.m_bad2
has thelambda
rewritten as a function.The error messages go away when I change
result = ...
toresult: List[B] = ...
, but that type annotation shouldn't be necessary, from looking at the definition ofreduce
) (In my original program, I got additional error messages, so I might have over-simplified this example.)Overloading of
reduce
infunctools.pyi
doesn't seem to be the problem -- I tried using my own definition ofreduce
but without the overloading, and got the same error messages.(For background: this example is a simplified version of some code that converts objects of class
C
to objects of classB
, with both classes having many subclasses.)Here are the error messages I got (program is attached as a TXT file):
This was run with
mypy --python-version=3.6 --strict-optional --check-untyped-defs --warn-incomplete-stub --warn-no-return --no-incremental --disallow-any-unimported --show-error-context --implicit-optional --strict --disallow-incomplete-defs /tmp/reduce_bug
reduce_bug.py.txt
The text was updated successfully, but these errors were encountered: