7 ms·
I like adding | as an alias for Union, and the PEP has lots of examples of where typing.Union gets gnarly really quick, but that doesn't seem like a great examp
by hannibalhorn 6y ago
I like adding | as an alias for Union, and the PEP has lots of examples of where typing.Union gets gnarly really quick, but that doesn't seem like a great example in the changelog:
def square(number: int | float) -> int | float:
return number ** 2
A TypeVar constrained to int and float, T = TypeVar('T', int, float), should be used instead to indicate that the return type is the same as the argument type, no?
- pansa2 6y agoThis example demonstrates why I don't understand Python's type annotations. They seem to be incompatible with the language's core principle of duck typing. Why would you constrain a function like `square` to only accept `int`s and `float`s? What if I want to square, say, a `fractions.Fraction`?
- heavyset_go 6y agoType annotations are just hints and aren't enforced at runtime. You can pass whatever you want into that function, and you can also create a union type with the Fraction if you want the annotations to match your application.
- pansa2 6y ago> You can pass whatever you want into that function Not really. Doing so won't cause an error at runtime, but it will produce an error when you run the type checker.
- musicale 6y agoYou seem to have removed the previous sentence which qualified the statement as "at runtime."
- pansa2 6y agoHow can I pass whatever I want into that function at runtime, while still satisfying the type checker?
- _flux 6y agoYou can use the Any type, or you can not annotate at all, though I'm not sure if the latter is something that passes some stricter modes of e.g. mypy.
- dragonwriter 6y ago> How can I pass whatever I want into that function at runtime, while still satisfying the type checker? Tell the type-checker to buzz-off by any number of means, including # type: ignore
- kortex 6y agoInterface typing > duck typing. With any sort of code completion, it's 1000x easier and more productive to figure out what goes where when the computer has some idea of the types of a given varaible, and hence what operations you can do to it. It's like duck typing with a built-in Audubon society taxonomy chart. You can always do whatever you want at runtime, it's still python. IMHO, duck typing is strictly inferior to interface typing. You'd define a `Number` interface which `int`, `float`, ect all implement.
- pansa2 6y ago> Interface typing > duck typing. Duck typing has been fundamental to Python for a long time. Do you think we're seeing a shift away from it? In the future, do you think "Pythonic" code will include significant use of explicit interfaces?
- dragonwriter 6y ago> Duck typing has been fundamental to Python for a long time. Do you think we're seeing a shift away from it? We have been since at least the introduction of abstract base classes; even in purely dynamic python, having the ability to more explicitly declare and interrogate intent than pure duck typing is frequently useful. > do you think "Pythonic" code will include significant use of explicit interfaces? Sure, as it already does via abcs. But it will also still use lots of duck typing, though over time more of it will be “static duck typing” by way of protocols. https://mypy.readthedocs.io/en/stable/protocols.html https://mypy.readthedocs.io/en/stable/protocols.html
- adamjb 6y agoThe "proper" way to annotate this function would be to use the numbers abstract base classes. https://docs.python.org/3/library/numbers.html https://docs.python.org/3/library/numbers.html
- maple3142 6y agoBut I don't think this will work on numpy matrix.
- adamjb 6y agoShould it? >>> import numpy as np >>> np.array("asdgh")**2 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: ufunc 'square' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
- maple3142 6y agoMatrix, not array. >>> import numpy as np >>> np.mat(((1,0),(0,1)))**2 matrix([[1, 0], [0, 1]])
- mkl 6y agoThat's a particularly confusing example to choose, because matrix squaring produces the same result as array (element-wise) squaring: >>> np.array([[1, 0], [0, 1]])**2 array([[1, 0], [0, 1]]) Here: >>> np.array([[1, 2], [3, 4]])**2 array([[ 1, 4], [ 9, 16]]) >>> np.mat([[1, 2], [3, 4]])**2 matrix([[ 7, 10], [15, 22]]) The real problem with the np.array("asdgh")**2 example is squaring doesn't make sense for character data. Matrix vs. array squaring has other issues too, as matrix squaring only works with square matrices: >>> np.mat([1, 2])**2 [...] LinAlgError: Last 2 dimensions of the array must be square >>> np.array([1, 2])**2 array([1, 4])
- hannibalhorn 6y agoThere is a numbers.Number for that - but yeah, that's another way in which it's just not a good example.. I think typing_extensions.Protocol helps support the general duck typing "any object that has method x", though there are some implementation issues w/ dataclasses and such..
- pansa2 6y ago> There is a numbers.Number for that That won't help if I want to square a matrix, or a polynomial. > typing_extensions.Protocol helps support the general duck typing "any object that has method x" Even if there's a `powerable` protocol that could be used to annotate `square` and `cube`, how would you annotate a slightly more complex function like `poly`? def square(x): return x**2 def cube(x): return x**3 def poly(x): return 3 * x**2 + 2 * x
- TylerE 6y agoIt wouldn’t be a “squareable” What’s you want is something like “commutative multiplication”
- thomasahle 6y agoWhile duck typing solves this problem on paper, how is a user to find out whether square really accepts a matrix? From comments? They are again limited by the authors imagination. From reading the source?
- anilakar 6y agoUsing maths to either oppose or support generic duck typing is just pointless, because it's easy to come up with counterexamples where a mathematical operation would or would not behave as expected. In quite a few cases where one would overload a mathematical operation to, say, sum two objects of certain type, it'd be better to explicitly type out the operation as a functor/lambda.
- pansa2 6y agoYes, read the comments or the source code. Or the documentation. Or `help(square)`. Or just try `square(Matrix([1, 2], [3, 4]))` in the REPL. How would you use type annotations to show that `square` accepts a matrix (as well as an int, float, rational number etc.)?
- zelly 6y agoType hints don't help performance either because the interpreter discards them. The hints are not enforced by CPython, so you now need a build tool instead of just running the script. The whole point of PEP 484 seems to be to enable autocomplete in Visual Studio Code.
- dragonwriter 6y ago> The whole point of PEP 484 seems to be to enable autocomplete in Visual Studio Code. It's to enable tooling, but not just autocomplete. The main purpose of typing is preventing type-related bugs, though making editor autocompletion and other editor information more robust is a not-insignificant additional benefit. PEP 484 (created 29-Sep-2014, accepted 22-May-2015) wasn't motivated by VS Code (announced April 29, 2015).
- ivalm 6y agoYour code should get type checked whenever you run tests and can help reveal subtle bugs (for example, allowing Optional but not handling None in all code paths)
- mkesper 6y agoAnother great value of running mypy on your code is that you ensure it can be compiled as a whole!
- chasontherobot 6y agoIt has nothing to do with any particular editor, it is for autocomplete and build time type checking in any editor and type checking in people's build chains.
- BozeWolf 6y agoPyCharm understands type hints for years now. Without using mypy btw. VSCode should be able to that, there should be one or more (either finished or half baked) plugins for it. Edit: Microsoft Python Language Server has it (i read)
- josefx 6y ago
- OJFord 6y agoDefine a protocol where __pow__ returns the type of self, and use that for the argument and return type of this function.
- alanfranz 6y agoYou need an interface to code something. Otherwise how can your square function work?
- Too 6y agoThe word you are looking for is structural typing. (as opposed to nominal typing) It's essentially type-safe duck typing. In the case of square, you say i want x and y to support the multiply-operator, but i don't care what type they are otherwise. Available since 3.8: https://www.python.org/dev/peps/pep-0544/ https://www.python.org/dev/peps/pep-0544/
- deleted 6y ago[deleted]
- hannibalhorn 6y agoI was just thinking that squaring an imaginary number results in a real number - that's a pretty crazy thing for a type system to handle, no? I guess that means the correct annotations would be more along the lines of: def square(number: numbers.Complex) -> numbers.Real: ... T = typing.TypeVar('T', numbers.Real) def square(number: T) -> T: return number ** 2 What a rabbit hole!
- pansa2 6y ago> squaring an imaginary number results in a real number However, in general, squaring a complex number results in another complex number.