Live data from Hacker News

Python developers are embracing type hints

pyrefly.org

351–360 of 581 posts

Re: Python developers are embracing type hints

#351

Earlier quoted context omitted.

That's not a benefit. That's a monstrosity. And, as you heavily imply in your post, type checkers won't be able to cope with it, eliminating one if the main benefits of type hints. Neither will IDEs / language servers, eliminating the other main benefit.

>And, as you heavily imply in your post, type checkers won't be able to cope with it I implied no such thing. literally said there's a language that already does this. Typescript. IDE's cope with it just fine. >That's not a benefit. That's a monstrosity. So typescript is a monstrosity? Is that why most of the world who uses JS in node or the frontend has moved to TS? Think about it.

The syntax is a monstrosity. You can also extract a proven OCaml program from Coq and Coq has a beautiful syntax.

If you insist on the same language for specifying types, some Lisp variants do that with a much nicer syntax.

Python people have been indoctrinated since ctypes that a monstrous type syntax is normal and they reject anything else. In fact Python type hints are basically stuck on the ctypes level syntax wise.

Re: Python developers are embracing type hints

#352

I actually don’t like python type hints! At my work we have a jit compiler that requires type hints under some conditions. Aside from that, I avoid them as much as possible. The reason is that they are not really a part of the language, they violate the spirit of the language, and in high-usage parts of code they quickly become a complete mess. For example a common failure mode in my work’s codebase is that some func…

> you better believe that every single admissible type will eventually be fed to this function That's your problem right there. Why are random callers sending whatever different input types to that function? That said, there are a few existing ways to define that property as a type, why not a protocol type "Indexable"?

Yes. It's not the type system that's broken, it's the design. Fix the design, and the type system works for you, not against you.

Re: Python developers are embracing type hints

#353
post #342

Earlier quoted context omitted.

from typing import Protocol, TypeVar T_co = TypeVar("T_co", covariant=True) class Indexable(Protocol[T_co]): def __getitem__(self, i: int) -> T_co: ... def f(x: Indexable[str]) -> None: print(x[0]) I am failing to format it proprely here, but you get the idea.

I give Rust a lot of points for putting control over covariance into the language without making anyone remember which one is covariance and which one is contravariance.

One of the things that makes typing an existing codebase difficult in Python is dealing with variance issues. It turns out people get these wrong all over the place in Python and their code ends up working by accident.

Generally it’s not worth trying to fix this stuff. The type signature is hell to write and ends up being super complex if you get it to work at all. Write a cast or Any, document why it’s probably ok in a comment, and move on with your life. Pick your battles.

Re: Python developers are embracing type hints

#354

Earlier quoted context omitted.

That doesn't sound like it'd have something to do with the dynamic nature of python. Type checking is a static analysis of the source code, so if you'd want something to be inferred dynamically, then you'll have to make use of generics: from typing import Callable class Pipeline[T]: def __init__(self, value: T) -> None: self._value = value def step[U](self, cb: Callable[[T], U]) -> 'Pipeline[U]': return Pipeline(cb(s…

I think this pipeline implementation does some things different from what I wanted (but did not precisely describe. It seems that each step is run right away, as it is "added", rather than collected and run when `terminate` is called. Also each step can only consume the result of the previous step, not the results of earlier steps. This can be worked around, by ending the pipeline and then starting multiple pipelines…

> Or is `class Pipeline[T]:` a short form of that?

Yes, since 3.12.

> Pipeline would need to change result type with each call of `add_step`, which seems like current type checkers cannot statically check.

Sounds like you want a dynamic type with your implementation (note the emphasis). Types shouldn't change at runtime, so a type checker can perform its duty. I'd recommend rethinking the implementation.

This is the best I can do for now, but it requires an internal cast. The caller side is type safe though, and the same principle as above applies:

    from functools import reduce
    from typing import cast, Any, Callable, Mapping, TypeVar


    def _id_fn[T](value: T) -> T:
        return value


    class Step[T, U]:
        def __init__(
            self,
            metadata: Mapping[str, Any],
            procedure: Callable[[T], U],
        ) -> None:
            self._metadata = metadata
            self._procedure = procedure

        def run(self, value: T) -> U:
            return self._procedure(value)
        

    TInput = TypeVar('TInput')
    
    
    class Pipeline[TInput, TOutput = TInput]:
        def __init__(
            self,
            steps: tuple[*tuple[Step[TInput, Any], ...], Step[Any, TOutput]] | None = None,
        ) -> None:
            self._steps: tuple[*tuple[Step[TInput, Any], ...], Step[Any, TOutput]] = (
                steps or (Step({}, _id_fn),)
            )
        
        def add_step[V](self, step: Step[TOutput, V]) -> 'Pipeline[TInput, V]':
            steps = (
                *self._steps,
                step,
            )
        
            return Pipeline(steps)

        def run(self, value: TInput) -> TOutput:
            return cast(
                TOutput,
                reduce(
                    lambda acc, val: val.run(acc),
                    self._steps,
                    value,
                ),
            )


    def _float_to_int(value: float) -> int:
        return int(value)


    def _int_to_str(value: int) -> str:
        return str(value)


    def main() -> None:
        step_a = Step({}, _float_to_int)
        step_b = Step({}, _int_to_str)

        foo = Pipeline[float]()\
            .add_step(step_a)\
            .add_step(step_b)\
            .run(3.14)
        print(foo)

        bar = Pipeline[float]()\
            .run(3.14)
        print(bar)


    if __name__ == '__main__':
        main()

Re: Python developers are embracing type hints

#355

Earlier quoted context omitted.

Yes, annotations allows you to use the declared types as they are, no strings.

It turns them into thunks (formerly strings) automatically, an important detail if you're inspecting annotations at run time because the performance hit of resolving the actual type can be significant.

TIL, thanks! It looks like 3.14 is also changing it so that all evaluations are lazy.

Re: Python developers are embracing type hints

#357

Python types - all the onus of static types, with none of the performance! I enjoy packages like pydantic and SOME simple static typing, but if I’m implementing anything truly OOP, I wouldn’t first reach for Python anyway; the language doesn’t even do multiple constructors or public/private props. Edit: as a side note, I was interested to learn that for more verbose type specification, it’s possible to define a type…

The most annoying part is that the type checking exists outside the regular runtime. I constantly run into situation where the type checker is happy, but the thing explodes at runtime or the type checker keeps complaining about working code. And different type checkers will even complain about different things regularly too. It's a whole lot of work making every part of the system happy and the result still feels extremely brittle.

Re: Python developers are embracing type hints

#358
I used python on a large code base for quite a while. Many team members did not like type hints, and a codebase that doesn't maintain type hints makes it harder to use them.

However, if I had a choice, rather than use typehints in python, I would much rather just use a statically typed language. Short, tiny scripts in python? Sure. Anything that grows or lives a long time? Use something where the compiler helps you out.

Re: Python developers are embracing type hints

#359

As a static typing advocate I do find it funny how all the popular dynamic languages have slowly become statically typed. After decades of people saying it's not at all necessary and being so critical of statically typed languages. When I was working on a fairly large TypeScript project it became the norm for dependencies to have type definitions in a relatively short space of time.

Huh. It's almost like these people didn't know what they were talking about. How strange.

Re: Python developers are embracing type hints

#360
post #342

Earlier quoted context omitted.

from typing import Protocol, TypeVar T_co = TypeVar("T_co", covariant=True) class Indexable(Protocol[T_co]): def __getitem__(self, i: int) -> T_co: ... def f(x: Indexable[str]) -> None: print(x[0]) I am failing to format it proprely here, but you get the idea.

I give Rust a lot of points for putting control over covariance into the language without making anyone remember which one is covariance and which one is contravariance.

Kotlin uses "in" and "out": https://kotlinlang.org/docs/generics.html
Post reply on HN