Why Today's Python Developers Are Embracing Type Hints

(pyrefly.org)

48 points | by ocamoss 4 days ago ago

56 comments

  • simonw an hour ago

    The thing that finally got me on board with optional type hints in Python was realizing that they're mainly valuable as documentation.

    But it's really valuable documentation! Knowing what types are expected and returned just by looking at a function signature is super useful.

    • smilliken an hour ago

      The best kind of documentation is the kind you can trust is accurate. Type defs wouldn't be close to as useful if you didn't really trust them. Similarly, doctests are some of the most useful documentation because you can be sure they are accurate.

    • lysace an hour ago

      Decent argument in principle. It still sucks for non-obvious types though:

      https://old.reddit.com/r/Python/comments/10zdidm/why_type_hi...

      Edit: Yes, one can sometimes go with Any, depending on the linter setup, but that's missing the point, isn't it?

      • mjr00 an hour ago

        As the top comment says, if you don't know or want to define the type just use Any. That's what it's there for.

        That entire Reddit post is a clueless expert beginner rant about something they don't really understand, unfortunate that it's survived as long as it has or that anyone is taking it as any sort of authoritative argument just because it's long.

        • pdonis an hour ago

          > if you don't know or want to define the type

          That's not the issue the reddit post is raising. The reddit post is pointing out that what a "type" is is not as simple as it looks. Particularly in a language like Python where user-defined types proliferate, and can add dunder methods that affect statements that involve built-in operations. "Just use Any" doesn't solve any of those problems.

          > just use Any.

          All the above said: not putting a type in at all is even easier than using Any, and is semantically equivalent.

          • mjr00 21 minutes ago

            The Reddit post falls under the case of "don't know" the type. If you want to allow users to pass in any objects, try to add and fail at runtime... that's exactly what Any is for.

            But the entire post is built upon the premise that accepting all types is good API design. Which it isn't, at all.

            • zahlman a few seconds ago

              > But the entire post is built upon the premise that accepting all types is good API design. Which it isn't, at all.

              Was Tim Peters also wrong way back in the day when he counseled Guido van Rossum to allow floats to be added to integers without a cast, like other popular languages?

  • tecoholic an hour ago

    I love typing in Python. I learnt programming with C++ and OOPs. It was freeing when I took up Python to note care about types, but I have come to enjoy types as I got older.

    But, boy have we gone overboard with this now? The modern libraries seem to be creating types for the sake of them. I am drowning in nested types that seem to never reach native types. The pain is code examples of the libraries don’t even show them.

    Like copy paste an OpenAI example and see if LSP is happy for example. Now I have gotten in this situation where I am mentally avoiding type errors of some libraries and edging into wishing Pydantic et al never happened.

    • AlienRobot 22 minutes ago

      My love for python was critically hurt when I learned about typing.TYPE_CHECKING.

      For those unaware, due to the dynamic nature of Python, you declare a variable type like this

          foo: Type
      
      This might look like Typescript, but it isn't because "Type" is actually an object. In python classes and functions are first-class objects that you can pass around and assign to variables.

      The obvious problem of this is that you can only use as a type an object that in "normal python" would be available in the scope of that line, which means that you can't do this:

          def foo() -> Bar:
              return Bar()
          
          class Bar:
              pass
      
      Because "Bar" is defined AFTER foo() it isn't in the scope when foo() is declared. To get around this you use this weird string-like syntax:

          def foo() -> "Bar":
              return Bar()
      
      This already looks ugly enough that should make Pythonists ask "Python... what are you doing?" but it gets worse.

      If you have a cyclic reference between two files, something that works out of the box in statically typed languages like Java, and that works in Python when you aren't using type hints because every object is the same "type" until it quacks like a duck, that isn't going to work if you try to use type hints in python because you're going to end up with a cyclic import. More specifically, you don't need cyclic imports in Python normally because you don't need the types, but you HAVE to import the types to add type hints, which introduces cyclic imports JUST to add type hints. To get around this, the solution is to use this monstrosity:

          if typing.TYPE_CHECKING:
              import Foo from foo
      
      And that's code that only "runs" when the static type check is statically checking the types.

      Nobody wants Python 4 but this was such an incredibly convoluted way to add this feature, specially when you consider that it means every module now "over-imports" just to add type hints that they previously didn't have to.

      Every time I see it makes me think that if type checks are so important maybe we shouldn't be programming Python to begin with.

      • dandiep 10 minutes ago

        Isn’t this solved in 3.14/PEP-649?

  • circadian an hour ago

    I really love Python for it's expedience, but type hints still feel like they don't belong in the language. They don't seem to come with the benefits of optimisation that you get with static typed languages. As someone who uses C and Julia (and wishes they had time for Rust), introducing solid typing yields better end results at a minimum, or is a requirement at the other end of the scale.

    The extra typing clarification in python makes the code harder to read. I liked python because it was easy to do something quickly and without that cognitive overhead. Type hints, and they feel like they're just hints, don't yield enough of a benefit for me to really embrace them yet.

    Perhaps that's just because I don't use advanced features of IDEs. But then I am getting old :P

    EDIT: also, this massively depends on what you're doing with the language! I don't have huge customer workloads to consider any longer..!

    • imron an hour ago

      > I don't use advanced features of IDEs

      I use vanilla vim (no plugins) for my editor, and still consider type hints essential.

  • imron 2 hours ago

    I enforce strong types on all Python code I’m responsible for - and make sure others don’t play fast and loose with dict[str, Any] when they could use a well defined type.

    Doing otherwise is just asking for prod incidents.

    • scuff3d 2 hours ago

      I worked on a project that did this. Drove me absolutely nuts. It's like having all the worst parts of a dynamic language and a static language with none of the benefits.

      I'd much rather just work in a statically typed language from the start.

      • imron an hour ago

        I too would much rather work in a statically typed language, but sometimes you have to work with what you’ve got.

        These systems are part of the core banking platform for a bank so I’d rather some initial developer friction over runtime incidents.

        And I say initial friction because although developers are sometimes resistant to it initially, I’ve yet to meet one who doesn’t come to appreciate the benefits over the course of working on our system.

        Different projects have different requirements, so YMMV but for the ones I’m working on type hints are an essential part of ensuring system reliability.

        • scuff3d an hour ago

          I'm not opposed to type hints, I use them everywhere. It's specially the strict linting.

          But it's a fair point. If you truly have no option it's better then absolutely nothing. I really wish people would stop writing mission critical production code in Python.

      • budro an hour ago

        Type hints seem fantastic for when you're in maintenance mode and want to add sanity back to a system via automated tooling.

        However for new projects I find that I'd much rather pick technologies that start me off with a sanity floor which is higher than Python's sanity ceiling. At this point I don't want to touch a dynamically typed language ever again.

      • lrobinovitch 2 hours ago

        What exactly drove you nuts? The python ecosystem is very broad and useful, so it might be suitable for the application (if not, reasonable that you'd be frustrated). With strict mypy/pyright settings and an internal type-everything culture, Python feels statically typed IME.

        • scuff3d an hour ago

          It's not even close compared to working with Java or Go or any language built with static typing in mind.

          To be clear, I'm not opposed to type hints. I use them everywhere, especially in function signatures. But the primary advantage to Python is speed (or at least perceived speed but that's a separate conversation). It is so popular specifically because you don't have to worry about type checking and can just move. Which is one of the many reasons it's great for prototypes and fucking terrible in production. You turn on strict type checking in a linter and all that goes away.

          Worse, Python was not built with this workflow in mind. So with strict typing on, when types start to get complicated, you have to jump through all kinds of weird hoops to make the checker happy. When I'm writing code just to make a linter shut up something is seriously wrong.

          Trying to ad typing to a dynamic language in my opinion is almost always a bad idea. Either do what Typescript did and write a language that compiles down to the dynamic one, or just leave it dynamic.

          And if you want types just use a typed language. In a production setting, working with multiple developers, I would take literally almost any statically typed language over Python.

          • Spivak an hour ago

            But TypeScript erases (its) types at runtime, exactly like Python. Python is Python's TypeScript. Whether you want TS or JS-like semantics is entirely dependent on whether you use a type checker and whether you consider its errors a build breaker.

            • scuff3d an hour ago

              I'm not sure what you're trying to say here. If you mean Python's type annotations are erased at runtime... Okay? It still has runtime type information. It's not "erasure" as that term applies to Java for example. And Typescript compiles down to JavaScript, so obviously it's runtime behavior is going to be the same as JavaScript.

              In my view it's always a mistake to try and tac static typing on top of a dynamic one. I think TS's approach is better than Python's, but still not nearly as good as just using a statically typed language.

            • ehutch79 an hour ago

              Not it doesn’t. It doesn’t throw errors, but they’re still introspectable in python, unlike typescript

            • AlienRobot 19 minutes ago

              Typescript requires a compiler to produce valid Javascript. Python 3 shoved types into Python 3 without breaking backwards compatibility I think.

              You would never have typing.TYPE_CHECKING to check if type checking is being done in TypeScript, for example, because type hints can't break Javascript code, something that can happen in Python when you have cyclic imports just to add types.

        • throwaway81523 an hour ago

          I would say mypy is better than nothing but it still misses things sometimes, and makes some signatures difficult or impossible to write. I use it anyway, but patched-on static typing (Erlang, Clojure, and Racket also have it) seems like a compromise from the get-go. I'd rather have the type system designed into the language.

      • minikomi 41 minutes ago

        Always fun to inherit a data-scientist derrived chunk of pytjon code for which every type hint is 'takes a dataframe' and 'returns a dataframe'..

  • zahlman 4 minutes ago

    It's the other way around, IMO: people who think the language should at least have type hints are now more willing to use it, now that there's better tooling for checking those hints.

  • Waterluvian 2 hours ago

    Typescript turned me into a believer but my gosh do python typings feel clumsy and quickly busy up files. I get why, and it’s not exactly realistic, but I wish a lot of it didn’t require an import.

    Whatever the solution is, it doesn’t include giving up on Python typings.

    • mrln 2 hours ago

      With the newest Python versions, most of the time I don't need typing imports!

      • letmeinhere an hour ago

        Yeah post 3.10 you don't need Union, Optional, List, Duct, Tuple. Any still necessary when you want to be permissive, and I'm still hoping for an Unknown someday...

        • maleldil 27 minutes ago

          > hoping for an Unknown someday

          Wouldn't that just be `object` in Python?

  • jmward01 11 minutes ago

    Type hints in python are just that, hints. Use them to help with clarity but enforcing them and requiring them everywhere generally leads to the worst of all worlds. Lots of boilerplate, less readable code and throwing away many of the features that make python powerful. Use the best language for the job and use the right language features at the right time. I see too many black or white arguments in the developer community, there is a middle ground and the best code is almost always written there.

  • scuff3d an hour ago

    Or you could just use a statically typed language and get a much better experience.

    • fnord77 an hour ago

      A entire class of bugs, wiped out by a thing called a "compiler". Gigahours of downtime and bug fixing globally prevented by a modest extra step up front. Great stuff.

  • biimugan an hour ago

    In addition to what others have mentioned, it also just makes it easier to come back later to a code base and make changes, especially refactoring. In many cases you don't even really have to add many type hints to get benefits from it, since many popular libraries are more-or-less already well-typed. It can also substitute for many kinds of unit tests that you would end up writing even 5 years ago. If you're an infrastructure engineer or data scientist that's usually just writing a lot of glue code, then it greatly helps speed up your output (I've found)

  • frou_dh an hour ago

    Because you almost always have a specific type in mind for that function parameter, so you might as well just write it down.

  • iandanforth 38 minutes ago

    I hate typing in Python. I spend a good chunk of my day fighting the type checker and adding meaningless assertions, casts, and new types all to satisfy what feels like an obsessive compulsive nitpicker. "Type partially unknown" haunts my dreams.

    Duck typing is one of the best things about Python. It provides a developer experience second to none. Need to iterate over a collection of things? Great! Just do it! As long as it is an iterable (defined by methods, not by type) you can use it anywhere you want to. Want to create a data object that maps any hashable type to just about anything else? Dict has you covered! Put anything you want in there and don't worry about it.

    If we ended up with a largely bug free production system then it might be worth it, but, just like other truly strongly typed languages, that doesn't happen, so I've sacrificed my developer experience for an unfulfilled promise.

    If I wanted to use a strongly typed language I would, I don't, and the creeping infection of type enforcement into production codebases makes it hard to use the language I love professionally.

    • maleldil 26 minutes ago

      > Need to iterate over a collection of things?

      Iterable[T]

      > Want to create a data object that maps any hashable type to just about anything else?

      Mapping[T, U]

  • donatj 2 hours ago

    Typings have pretty cleanly been getting added to PHP over the last decade. I'm kind of surprised Python's are so bolted on by comparison

  • lacker 2 hours ago

    Type hints are much easier to use nowadays than they were a few years ago, because the agentic tools like Claude Code are very good at converting an existing codebase to using type hints.

    • OutOfHere 2 hours ago

      The flip side of it is that Claude Code will have a very bad time in a code base with grossly unsatisfiable or conflicting types (where a type checker would fail the project). A human should always first ensure that the types are broadly correct, with or without the assistance of code tools.

      • Waterluvian 2 hours ago

        I can empathize with the code tools. Sometimes I’ll read Python code and have no idea at first glance if these are type bugs or creative coding by the dev. Python is incredibly flexible. Though I think most of the time you really shouldn’t be using the flexibility.

  • throwaway81523 an hour ago

    Oh datatype hints. I ignored the headline on first scan, thinking it was about font metrics.

  • LordDragonfang 2 hours ago

    The biggest reason I use typehints is that VSCode's intellisense relies on them - and I know I've missed one when typing a dot doesn't give me the method I'm expecting.

  • morkalork 2 hours ago

    They do remove an entire class of avoidable errors in code bases of course people will embrace it.

  • quotemstr 2 hours ago

    Type hints in dynamic languages are great, but I wish they came with deeper integration into the language runtime for validation and for optimizer setup.

    If I have a function that takes an int, and I write down the requirement, why should a JIT have to learn independently of what I wrote down that the input is an int?

    I get that it's this way because of how these languages evolved, but it doesn't have to stay this way.

    • dmurray an hour ago

      That was the original intent of mypy, to allow a subset of Python to be interpreted by a JIT or transpiled to a compiled, statically typed language.

      The type hints proved to be useful on their own so the project moved past what was useful for that purpose, but a new JIT (such as the one the upcoming CPython 3.14 lays the groundwork for) could certainly use them.

  • LoganDark 2 hours ago

    I think I've always used Python type hints, but that was partially because early versions of Discord.py relied on them (maybe it still does). But it was also because I like to be able to mentally verify my code's correctness before running it, and waiting for runtime errors is comparatively a huge waste of time (in my opinion).

  • bgwalter an hour ago

    Because they follow any corporate initiative that gives them something to do, even if the type hints are the most unreadable and hackish form of typing in existence.

  • secondcoming 2 hours ago

    I recently had to debug someone else's Python code and trying to figure out what variables are was a massive headache, especially coming from C++.

    • skydhash 2 hours ago

      I do not program that much in python, but I believe the general accepted wisdom in dynamic languages was explicit name and load of documentations (as comments and docstrings).

      • maleldil 23 minutes ago

        > explicit name and load of documentations (as comments and docstrings).

        Which can be out of date are often missing. Might as well use type-hints that can be statically checked.

      • imron 2 hours ago

        Absolutely the general accepted wisdom in line with best practices - that are often ignored

    • rcfox an hour ago

      In Python, every variable is either defined or imported in the file in which it's used, so you always know where to find it. (Assuming you don't do `from foo import *`, which is frowned upon.)

      In C++, a variable might be defined in a header or in a parent class somewhere else, and there's no indication of where it came from.

      • maleldil 21 minutes ago

        How does this help when trying to determine the parameters a function takes? You have to either hope that the name is descriptive enough or that the function is well-documented. Failing that, you need to read the code to find out.

    • Akronymus 2 hours ago

      Even c++ feels clunky in terms of types to me. Though that's probably down to me preferring a more complete type system like haskell has