November 27th, 2024

Python type hints may not be not for me in practice

Chris Siebenmann expresses skepticism about Python's type hints for small tasks, finding them cumbersome. He prefers adding them post-stabilization for documentation, envisioning a system allowing distinct types without upfront details.

Read original articleLink Icon
Python type hints may not be not for me in practice

Chris Siebenmann reflects on his experience with Python's optional type hints, expressing skepticism about their practicality for small programming tasks. He initially considered using type hints but ultimately decided against it, finding that they require him to define concrete types for basic data structures like dictionaries and lists, which can be cumbersome. He notes that while he often recognizes distinct types, he prefers not to specify their exact forms, as the typing documentation does not provide a straightforward way to create distinct types without losing flexibility. Siebenmann acknowledges that adding type hints after code stabilization might offer some benefits, such as documentation and error prevention when revisiting the code later. However, he believes that the common advice to write type hints during development may not apply to his short programs, where adding them afterward is manageable. He concludes that while practicing type hints could make them easier to use, his infrequent programming means he would need to relearn them each time. His ideal scenario would involve creating distinct types for function arguments and returns, allowing for type checking without needing to define every detail upfront.

- Chris Siebenmann is skeptical about the practicality of Python type hints for small programs.

- He finds type hints cumbersome as they require defining concrete types for basic data structures.

- Adding type hints after code stabilization may provide documentation and error prevention benefits.

- Siebenmann believes that the advice to write type hints during development may not suit his programming style.

- He envisions an ideal type hinting system that allows for distinct types without upfront detail specification.

Link Icon 38 comments
By @aSanchezStern - 5 months
The thing that the author says they would prefer is already in Python, it's called NewType (https://docs.python.org/3/library/typing.html#typing.NewType)

They say "...so I can't create a bunch of different names for eg typing.Any and then expect type checkers to complain if I mix them."

`MyType = NewType('MyType', Any)`

is how you do this.

At the end, they suggest a workflow: "I think my ideal type hint situation would be if I could create distinct but otherwise unconstrained types for things like function arguments and function returns, have mypy or other typing tools complain when I mixed them, and then later go back to fill in the concrete implementation details of each type hint"

That's just doing the above, but then changing the `NewType('MyType', Any)` to something like `NewType('MyType', list[dict[str, int]])` later when you want to fill in the concrete implementation.

By @joeyagreco - 5 months
> After the code has stabilized I can probably go back to write type hints [...] but I'm not sure that this would provide very much value.

I think most developers who revisit their projects 6+ months later would disagree with the second part of this statement.

My typical flow for "quick scripts" is:

on first pass I'll add basic type hints (typing ":str" after a func param takes .2 seconds)

for more complex data structures (think a json response from an api), dict (or typing.Dict) work fine

if you want a Python project to be maintainable, type hints are a requirement imho.

By @emeryberger - 5 months
I agree that writing type hints can be painful, especially if you are starting with a large code base that is mostly untyped. You might consider using RightTyper (https://github.com/RightTyper/RightTyper) - basically run your Python 3.12+ program with it, and it will add type hints to your code. It’s fast, basically automatic, and by design RightTyper avoids overfitting to your types, letting a type checker like MyPy surface edge cases. In effect, the type checker becomes an anomaly detector (Full disclosure, I am one of the authors of RightTyper.)

From the GitHub page:

RightTyper is a Python tool that generates types for your function arguments and return values. RightTyper lets your code run at nearly full speed with almost no memory overhead. As a result, you won't experience slow downs in your code or large memory consumption while using it, allowing you to integrate it with your standard tests and development process. By virtue of its design, and in a significant departure from previous approaches, RightTyper only captures the most commonly used types, letting a type checker like mypy detect possibly incorrect type mismatches in your code.

By @tasn - 5 months
The Python type system is pretty bad, but it's still 100x better than not using types. We are heavy users of the (Rust) type system at Svix, and it's been a godsend. I wrote about it here https://www.svix.com/blog/strong-typing-hill-to-die-on/

We also use Python in some places, including the shitty Python type-system (and some cool hackery to make SQLAlchemy feel very typed and work nicely with Pydantic).

By @agubelu - 5 months
Type hints are nice, until you have to interact with a library that isn't type-hinted, and then it very quickly becomes a mess.

I don't know how other IDEs behave, but VScode + the Python extensions try to infer the missing hints and you end up with beauties such as `str | None | Any | Unknown`, which of course are completely meaningless.

Even worse, the IDE marks as an error some code that is perfectly correct, because it somehow doesn't match those nonsensical hints. And so it gives you the worst of both worlds: a lot of false positives that you quickly learn to ignore, dooming the few actual type errors to irrelevance, because you'll ignore them anyways until they blow up at runtime, just as it'd happen without typehints.

By @greatgib - 5 months
The logic of type hint is not bad but sadly I think that type hint are making python source code messy and unreadable.

I'm missing a lot simple functions with explicit argument names and docstrings with arguments types and descriptions clearly but discreetly documented.

It was one big strength of Python to have so simple and clean code without too much boilerplate.

Also, I have the feeling that static typing extremist are trying to push the idea that type hinting allows to ensure to not mix types as it would be bad. But from my point of view the polymorphic and typing mixing aspect is a strong force of Python.

Like having dictionaries that are able to hold whatever you want is so incredible when you compare to trying to do the equivalent in Java for example.

One part where I find type hint to be wonderful still is for things like pydantic and dataclasses!

By @maleldil - 5 months
Something I didn't see mentioned much here is refactoring. Refactoring without types is like walking in the dark. You have to check everywhere to see how your changes impact other code, and you'll certainly miss some and only find out in production. With typing, when you change your type signature, you can just run the checker and get a list of places you need to change.
By @linsomniac - 5 months
Similar to the author, I infrequently write Python code (though I have a long history with it), but I feel quite the opposite about type hints. A few specific comments:

- The LLMs can really help with typing tricky situations. If your editor can't already tell you what to use, asking an LLM usually can give me the answer.

- Type annotations for code that might change is a lifesaver, because when I change it later on I now get a bunch of conflicts where I've used it using the old way.

- Feel free to add annotations where it makes sense and is easy, and if something doesn't make sense or it is too hard to figure out the right type, you can skip it and still gain the benefits of using it elsewhere.

- Annotations don't "force you to think about types", you already are thinking about types. They let you think a bit less about types I would argue, because they're documented in function calls and returns. "Can I read() from input_file, or do I need to open()read()?" "input_file:Path" makes it better documented, without encoding the object type in the name.

I'm coming up on 30 years of using Python, and I never really missed typing, but honestly I write basically all of my new code with annotations because of the IDE benefits I get from it. I love that the Python implementation allows me to get the benefits without forcing it on me. In my distant past I very much loved coding in C, but was quite happy with Python's lack of strict typing. This feels like a good middle-ground.

By @andrewstuart - 5 months
Program the way you like it and it should be fun.

If you are at work doing professional programming then typing helps avoid bugs and makes programming more of a reliable and robust process.

But doing your own thing, doing little utilities, banging out quick stuff, do exactly what makes you happy.

Programming should be fun not a chore and if types make it a chore for you then drop them.

By @maxbond - 5 months
I think TypeScript provides a lot more of the freedom the author is looking for. For instance, you can say, "the type of this argument is whatever is returned by that function."

Personally I find myself more comfortable and productive using types. Stating your types has a similar benefit to journaling, in my view. It's a forcing function for clarifying your ideas about the problem domain. Some perceive this as overhead, I perceive this as front loading. If my ideas are murky, I will run into trouble sooner or later. The later it is, the more painful it will be.

I think it largely comes down to different habits of working and thinking. I don't think one way is superior to another inherently (though types are important for collaboration), but that different people work in different ways.

By @KaiserPro - 5 months
Type hinting in python is a bit of a sticky plaster.

We have pyre enforcement at work, the problem is, that it has been gradually turned on over time, so some stuff is pyre compliant (or just strategically ignored) and some stuff isnt, so when you open some old code to do something, you have a million errors to deal with.

That would be fine if types were enforceable. in runtime type hinting does shit all.

I would dearly love a "strict" mode where duck typing is turned off and variable are statically typed. However I suspect that will never happen, even though it'd speed up a load of stuff if done correctly (type inference happens a lot)

I suspect to use type hints properly, I'd need to think a bit more C-like and create dataclasses as types to make things more readable, rather than using Dict[str,int] or what ever.

By @craftkiller - 5 months
> In writing this it occurs to me that I do often know that I have distinct types (for example, for what functions return) and I shouldn't mix them, but I don't want to specify their concrete shape as dicts, tuples, or whatever. [...] Type aliases are explicitly equivalent to their underlying thing, so I can't create a bunch of different names for eg typing.Any and then expect type checkers to complain if I mix them.

It sounds to me like you're describing the NewType pattern which is just slightly farther down the page you linked in the article.

https://docs.python.org/3/library/typing.html#newtype

By @truculent - 5 months
The problem (in my opinion) is that Python gives you the tools (and perhaps even encourages you) to write code that would benefit from typing.

It's perfectly feasible to write maintainable, well-designed code in a dynamic language. I've worked with some extremely robust and ergonomic Clojure codebases before, for example. However, in Clojure, the language pushes you into its own "pit of success".

Personally, I never feel that with Python.

By @pansa2 - 5 months
The biggest issue with Python type hints for me isn't the hints themselves, it's that they encourage people to write overly complex, verbose code just to satisfy the type checker.

Code like this [0] could simply be 3 functions. Instead it's 3 classes, plus a base class `AstNode`, just so the author can appease the type checker by writing `body: List[AstNode]` instead of the dynamically-typed `body = []`.

[0] https://gist.github.com/sportsracer/16a1e294966cfba83ba61e6a...

By @danjl - 5 months
This has all happened before. This will all happen again. Everyone felt the same way about TypeScript. Types feel annoying at first, if you lived without them. Using untyped libraries is annoying until they all have types, which happens over time. Types prove their worth every time.
By @Hackbraten - 5 months
> yet another Python thing I'd have to try to keep in my mind despite it being months since I used them last.

Typing hints are also a moving target: they have changed, sometimes significantly, on every minor Python release since they came to be.

The `Optional` type came and went (being replaced by the new Union syntax.) Type classes are usually born in the `typing` module, then some of them get moved to `collections`, `abc`, or `collections.abc`. Some types have even been moved several times. `TypeAlias` came and went (replaced by `type`). `List` became `list`. `Tuple` became `tuple`. Forward declarations require a workaround by using string literals. But in Python 3.14, they no longer do, and the workaround will become deprecated.

I'm an evangelist for static type checking, and I never write a Python function signature without complete typing annotations. I also think that typing annotations in Python are evolving in a good way. However, for long-lived Python scripts, I highly recommend that developers are aware of, and factor in, the effort necessary to keep up with the evolution of static typing across Python versions. That effort spent on migrating is going to come on top of the mental load that typing hints already add to your plate.

By @gorgoiler - 5 months
The same applies to tests, maybe docs too.

For x in tests, type annotations, and documentation*:

If you write your x first then you have to decide what your API is. This is great if you want to think about your API. Sometimes though you just want to get down to it and play around with a new idea. Either way is fine.

As soon as you start sharing code or patching production code or patching someone else’s production code, one must insist on seeing some kind of x. Having x around the outside of a system — rather than requiring x be added throughout the entire system — is often good enough.

*The useful, architecture kind.

By @sesuximo - 5 months
> PPS: I think my ideal type hint situation would be if I could create distinct but otherwise unconstrained types for things like function arguments and function returns, have mypy or other typing tools complain when I mixed them

Cleaner/safer function args and return types is a common motivation for dataclass. has benefits over many/complex args besides typing too.

By @solidsnack9000 - 5 months
It seems like the author is looking for the ability to specify types as `typeof <function>:arguments` and `typeof <function>:return`. I can see how this could make prototyping easier. It is also helpful for cases (not uncommon in Python) where you're just proxying another function.
By @thebigspacefuck - 5 months
This is what we ended up using with mypy so we could add type checks to our CI without having to fix every single typing error:

https://github.com/orsinium-labs/mypy-baseline

By @Neywiny - 5 months
The note about creating your own data types is interesting. I used to be heavily dependent on tuples. Admittedly dicts would've saved me here but I liked the efficiency of numeric indexing. Anyway, any time I changed ordering or anything I'd have countless headaches. I started using dataclasses and never looked back. I love turning the type checker on in vscode and seeing it correctly catch future issues. Only problem is when libraries are indirectly hinted, as others have pointed out
By @bmitc - 5 months
It takes mere seconds to write type hints, and with modern auto-complete tooling or Copilot, it's basically automatic. It goes a long way to use tools like MyPy to verify your code and also provide documentation for users of your code. If you don't want to write type hints, don't use a dynamically typed language.
By @dzonga - 5 months
this is not a just a python problem but a problem in many dynamic languages.

switching to the typed variants whether typecript, python type-hints, mypy etc will force you to do the dance to make the compiler happy instead of working on code.

which is why for me - JSDoc is really good - it uses types for documentation and ends there.

By @solarkraft - 5 months
It’s kind of cool that type hints can be reflected on to do things (see Pydantic). Other than that I find it pretty cumbersome to use in practice, coming from TypeScript. Semi-relatedly I also dislike Python’s different ways to access objects/dicts, it feels arbitrary and cumbersome.
By @terminalbraid - 5 months
Sometimes I feel like we need an analog to javascript/typescript. Ptypethon if you will.
By @aegis4244 - 5 months
Is that a double negative in your title ? Or is it an inside joke I didn't get ?
By @nmca - 5 months
The problems with python types are:

A) The type system is fairly bad, as type systems go (forgivable) B) the type checkers are, for large codebases, excruciatingly slow, to the point that the tests are faster!!

The second is not forgivable.

By @adsweedler - 5 months
If you could snap your fingers and have your type hints update to match your code, it wouldn’t get in the way of your work.

Hyperbolically: You have to be able to edit code at the speed of thought - whatever it takes - or else programming languages cease to be a more useful tool than just thinking.

If you type slower than you think, or can’t do the type-hint-based textual translation as quickly as you think, then… yeah - it’s not good for you.

The advice I’d wanna hear for myself is: just get better. But the advice I’d give to my coworkers is: have explicit domains where you’re able to do whatever is most efficient and effective, and then when you hand off data to the next subsystem - obey a contract. A schema. Be that type hints or a .proto file or a database schema or an API. Doesn’t matter.

By @BiteCode_dev - 5 months
That's why they are not unspecified to be optional.
By @est - 5 months
IMHO, type hints should only serve two purposes:

1. design a memory layout for faster execution

2. press dot and get suggestions in IDE

other usage of types brings more problem than it solves.

By @liontwist - 5 months
Python continues to show it will adopt any feature with online interest without guiding principle.
By @4ad - 5 months
> Types prevent me from writing code that I don't understand.

Yes, thats the point.

By @ethagnawl - 5 months
This post title gives me a headache.
By @propagate97 - 5 months
Doesn't know how the first two things about python type hints. Must be shit. Great article...
By @travisgriggs - 5 months
I typehint the stuff that is easy. My observations about typehinting in Python track the 80:20 rule or even a 90:10 rule. You get about 80% benefit for typhinting the easy 20%.
By @scoofy - 5 months
My objection to strong types in python is philosophical. Python mimics natural language, and natural language rejects strong types for context resolved ambiguity.

In the way we resolve these issues in natural language, we can resolve bugs in python, that is, “do you mean integer ’3’ or string’3’” instead of insisting we define everything always forever.

To me, people who use type hinting are just letting me know they have written code that doesn’t check in line.