Skip to content
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

Allow specifying length of sized object #7626

Open
jtrakk opened this issue Oct 4, 2019 · 5 comments
Open

Allow specifying length of sized object #7626

jtrakk opened this issue Oct 4, 2019 · 5 comments

Comments

@jtrakk
Copy link

jtrakk commented Oct 4, 2019

Sometimes I want to specify the size of a container. This could be done manually with casts, but it would be really cool if Mypy could figure this out automatically. __len__() is guaranteed to return an int, and since a is defined as a literal the match could be statically inferrable. The same is true of other container types.

from typing_extensions import Protocol, Literal


class Char(Protocol):
    def __len__(self) -> Literal[1]:
        ...


a: Char = "X"

Mypy reports

error: Incompatible types in assignment (expression has type "str", variable has type "Char")
note: Following member(s) of "str" have conflicts:
note:     Expected:
note:         def __len__(self) -> Literal[1]
note:     Got:
note:         def __len__(self) -> int


Mypy 0.720
CPython 3.7.3

@msullivan
Copy link
Collaborator

Could you expand on the motivations for this a bit more?

@jtrakk
Copy link
Author

jtrakk commented Oct 6, 2019

Sometimes I receive an iterable that should have exactly one element and I need to extract it. The most common way to do this is

x = next(items)

but that fails to detect if there are too many items, so we can use

[x] = items

which raises ValueError if there are too many.

Ideally we could check this at compile time, rather than having a runtime exception, by specifying

items: Char

or more generally

items: Sized[1]

@gvanrossum
Copy link
Member

But in order to implement a useful check, you don't just need a mechanism to specify the expected size -- you also need to implement the inference needed to keep track of the length of the value passed in. It looks to me as if you're thinking that that size is available, which it would be at run time (of course) -- but mypy doesn't execute the code, it just reads the code and tries to understand its meaning.

In order to infer the length of a list, it would have to do inferences like the following:

def f(arg: List[int]):
    arg.extend(arg[:2])
a = []  # length is 0
a.append(42)  # length is now 1
f(a)  # what is a's length now?

IOW I don't believe this is as simple as you think.

@ilevkivskyi
Copy link
Member

I think we can support fixed size collections, for example for tuples. But IMO this is pretty low priority.

@ethanhs
Copy link
Collaborator

ethanhs commented Oct 18, 2019

It may also be nice to support code like:

if len(a) == 1:
   # a now meets the protocol requirements

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants