-
Notifications
You must be signed in to change notification settings - Fork 767
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
Issue about type annotation #822
Comments
You have a misunderstanding of how type systems and type checking work. It can be confusing at first if you haven't used a typed language. For details of type checking within Python, please refer to PEP 483 and 484. Let me explain some concepts based on the two examples you provided. In your first example, the declared type of In your second example, you have declared that If your intent is for from typing import TypeVar
class A:
pass
class B(A):
utils: int = 13
pass
_T = TypeVar("_T", bound=A)
def func2(x: _T) -> _T:
return x
y: B = func2(B())
y.utils = 15 Hope that helps. |
@erictraut Thanks for your detailed explanation! It makes me clear about the type narrowing. And I realize that the declaration goes first, and then narrow to the method return type. However, there still some cases confusing. import numpy as np
c: np.ndarray = np.bincount([1, 1, 3, 3, 4]) If I run the program, This is certainly not correct and will cause violation, and should be fixed (by some stub pyi files perhaps?). I still have questions about the |
If you want to enable type checking, annotated libraries are very important. Pylance will do its best to infer types in the absence of annotations, but inference is prone to errors, and you'll run into many issues. Parts of numpy are even delivered as native libraries, so there's no Python code for Pylance to use as a source for inference. So you really need type stubs for type checking to work. Try data-science-types and see if that meets your needs. |
Yes, I admit that using Well, it seems not. And Pylance will keep the wrong prediction forever no matter what I do in the code (unless I write a I think it might need some feature improvement to support this? |
Numpy support is tracked in #150. Numpy itself may ship with stubs soon (depending on their quality). I'd think you'd be able to manually override the type and stick a |
@jakebailey |
This shows that annotating the variable works (what you described as a fix), it's just that |
Nope? Because |
You can certainly declare the types of variables within your own code. However, you can't declare the return types of library functions in your own code. You would need to write a stub file to do that. You can call the from typing import cast
# Cast is required because np.bincount function is not annotated.
c = cast(np.ndarray, np.bincount([1, 1, 3, 3, 4])) |
My mistake, I missed the yellow. |
I guess I'm confused as to why annotating it doesn't work; I would have expected |
@erictraut To clarify, the expected behavior should be: If the function return type is conflict with the variable declaration, raise Error (or warning?), but the variable type should still be the declaration type. So it is for the
But I think I might understand incorrectly for the word |
Most users don't care about static type checking. For those that do, Python is going to be inconvenient until library authors provide complete and accurate type annotations. We're doing our best to accelerate that. Yes, you are correct about the expected behavior. x: int = 3
reveal_type(x) # Literal[3]
x = 5.4 # This line generates an error because 5.4 is a float
reveal_type(x) # int In the above example, the type of |
@erictraut |
Thanks, you are correct. I've tested with So the current issue is to get the expected behavior for We just need to solve the conflict between |
If type checking is off, you will not see any type-checking errors. You will receive completion suggestions and other language features but no type checking. Why do you care what types Pylance predicts as long as you're getting the best possible completion suggestions in most cases? Pylance intentionally changes its behavior when type checking is disabled to favor better completion suggestions based on the types of the values assigned, versus the declared types. The assumption is that if type checking is disabled, you don't care about the declared types as much as the actual assigned types. What you're proposing is that we don't change the behavior between the two modes. That may address the specific examples you've cited, but I think it will create even problems in more situations. In other words, I think such a change would be a net negative for most Pylance users. We'll discuss this internally and get back to you, but right now I'm not inclined to change the behavior. |
Yes. I don't care about the type-checking errors. I just want completion suggestions. The problem is caused by Pylance getting wrong type predictions and users can't fix it manually without using I know it might be difficult to handle. Just hope we can finally get a good solution. import numpy as np
c: np.ndarray = np.bincount([1, 1, 3, 3, 4])
c.tolist() |
It's actually trivial to change the behavior and make it consistent. It simply involves deleting an if statement in the code here: https://github.com/microsoft/pyright/blob/f1da893256092f55549c1b38710bf4aec9a9f075/packages/pyright-internal/src/analyzer/typeEvaluator.ts#L2497. I'm still not convinced it's a good tradeoff though. I think it will fix some cases but break even more of them. |
Thanks a lot for your patient discussion. Hope it can get solved! |
We had a good internal debate about the pros and cons of making this change. We decided to make the change and get feedback. If many Pylance users dislike it, we could revert it or look for some other solution. |
You guys are really working efficiently! So damn quick, which violates my previous impression on Microsoft😂 |
This issue has been fixed in version 2021.1.1, which we've just released. You can find the changelog here: https://github.com/microsoft/pylance-release/blob/main/CHANGELOG.md#202111-13-january-2021 |
I personally support this change, I have type-checking off, and I prefer to have a way to force a type without using |
@erictraut ExpectationLet me first put my expectation here (2 cases): a: set[int] = {} # 'a' is set[int]
a.add(4) # with good linting, 'a' is set[int]
a = list(a) # 'a' is list[int]
a.sort() # with good linting, 'a' is list[int] and a: set[int] = {1,2,3} # 'a' is set[int]
a.add(4) # with good linting, 'a' is set[int]
a: list[int] = list(a) # 'a' is list[int]
a.sort() # with good linting, 'a' is list[int] BugTo describe the bug, let's see a working-well case first (with automatic type annotation): a = {1,2,3} # 'a' is set[int]
a.add(4) # with good linting, 'a' is set[int]
a = list(a) # 'a' is list[int]
a.sort() # with good linting, 'a' is list[int] However, sometimes we have to construct a: set[int] = {1,2,3} # 'a' is set[int]
a.add(4) # with good linting, 'a' is set[int]
a = list(a) # 'a' is still set[int]
a.sort() # with no linting, 'a' is set[int] From User's end, I try to fix the wrong annotation by a: set[int] = {1,2,3} # 'a' is list[int]
a.add(4) # with no linting, 'a' is set[int]
a: list[int] = list(a) # 'a' is list[int]
a.sort() # with good linting, 'a' is list[int] I think the current behavior is not what we expect. And if anyone think this shall be a new issue different from this one, I'm okay with that. |
The current behavior is consistent with how type checking works in Python. See PEP 484 and PEP 526 for details. When you declare the type of a variable, it is the job of a type checker to enforce that type and report an error if you attempt to assign a value to that variable that does not conform to that type. If your intent is for the variable to accept different types, you can declare it with a union type. a: Union[set[int], list[int]] = {1,2,3}
a.add(4)
a = list(a)
a.sort() Or you can use a different variable name for a separate type. a: set[int] = {1,2,3}
a.add(4)
b = list(a)
b.sort() |
@erictraut |
I think we should allow type modification after function returns. This is essential for
Union
and subclass.See 2 cases below:
The text was updated successfully, but these errors were encountered: