Writing `body: list[AstNode]` lets you statically know what elements you'll get when you do `body[i]` or iterate over it. If you don't specify the type, you don't know what you're getting, and you have to rely on always passing the correct objects around. I'm sure you've faced bugs where you expected something from a list and got something else.
Note that you only need `body: list[AstNode] = []` if you declare an empty container since the type checker cannot infer the type. If you're using list comprehensions or initialising the list with an element, the type checker will infer the type. You can even have a heterogeneous list with objects from multiple types, and the type checker will infer the type as the union.
In modern typed Python, you usually only annotate function signatures or stuff like dataclasses.
> Writing `body: list[AstNode]` lets you statically know what elements you'll get when you do `body[i]`
Don't get me wrong, I understand the benefit of the type hint - and if typing `: list[AstNode]` was all it took to get that benefit it would be a no-brainer. But that's not all it took - instead, to pass the type checker the entire script has become twice as long as it needs to be. The actual logic is hidden among multiple class definitions which are all unnecessary except to satisfy the type checker.
I agree with Armin Ronacher [0]: "types add value and they add cost". Perhaps the cost is worth paying for most programs - but there are plenty of other languages that support that way of working. For those programs where the cost might outweigh the benefits, I used to love writing Python as a more concise alternative to those languages - but instead nowadays it has become a poor attempt at mimicking them.
> there are plenty of other languages that support that way of working
I'd use them if I could, but I'm trapped in Python for several reasons. If I could use Rust, Ocaml, etc., I'd do that. But my choice is between untyped and typed Python only, and I strongly believe that typed Python is much better.
Note that you only need `body: list[AstNode] = []` if you declare an empty container since the type checker cannot infer the type. If you're using list comprehensions or initialising the list with an element, the type checker will infer the type. You can even have a heterogeneous list with objects from multiple types, and the type checker will infer the type as the union.
In modern typed Python, you usually only annotate function signatures or stuff like dataclasses.