Title: Alternative type-first annotation syntax: type: name = value
Body:
Summary
I’d like to propose an alternative syntax for variable type annotations where the type precedes the variable name, as an optional complement to PEP 526’s existing name: type = value form:
str: name = "Laura"
int: age = 20
float: height = 1.90
bool: is_developer = True
Developers coming from C, Java, or Go are used to reading the type first when scanning a declaration (String name = "Laura";). Putting the type first could make declarations easier to scan visually, especially in code with many annotated variables, and could make columns of type-aligned declarations easier to skim in editors.
Known problems I’m aware of
This directly conflicts with PEP 20 (“There should be one — and preferably only one — obvious way to do it”). I’d like to hear whether the community thinks the readability gain is worth having two syntaxes for the same thing.
There’s a real grammar ambiguity concern: a statement starting with str: name could be confused with a dict literal key ({str: name}) or other existing uses of : in expression context. I haven’t worked out whether this is resolvable without breaking existing valid code — happy to hear from people who know the CPython grammar/parser better than I do.
Tooling cost: black, ruff, mypy, pylint, and every IDE would need to support both forms, which could fragment style across the ecosystem.
Alternatives already considered
Just using formatters (black/ruff) to visually align existing PEP 526 annotations instead of changing syntax.
Implementing this as a linter/formatter plugin or stub-file convention rather than a runtime/grammar change.
I’m posting here first (rather than drafting a full PEP) specifically to get feedback on whether this is worth pursuing further, and especially on the grammar ambiguity issue. Genuinely open to being told this isn’t a good idea — I’d rather find that out here than after writing a full PEP.
I don’t think this will ever be accepted. A different syntax for something we already have syntax for that’s offers nothing on top is a hard if not impossible sell. One could also argue against this with the same argument: People coming from Rust, TypeScript, Kotlin, etc are familiar with name: type = value.
Tangential: I really dislike type name = value. I much prefer Python’s name: type = value (same for Rust, TypeScript, Kotlin, etc)
Apart from (dis)benefits and feasibility and preferences, how would the interpreter, tools, humans and agents discern the new type: name form from the existing name: type form?
Types are not reserved words in Python, so after implementing your proposal int: object = 42 could mean an int instance named object with value 42, or an object-type instance named int, which now is 42 but will be ‘hello’ later.
The syntax is identical to the current one, except for flipped sides. How would Python know, given a : b = c, which is the type and which is the variable? Would it have to check if a or b already exist in scope? Would it be some magic import?
Developers coming from C, Java, or Go are used to reading the type first when scanning a declaration (String name = "Laura";).
Not true for Go. Developers working in multiple languages already have to adjust to various differences (indentation vs braces being the most obvious example). The colon in the current syntax does help distinguish it from the C-style syntax IMO.
You’re right, and that’s actually the weakest part of my own proposal. “Familiarity” is not a one-way argument — plenty of people are coming from Rust/TypeScript/Kotlin too, and for them name: type is already the familiar form. I don’t think I can win that argument on familiarity alone, and I probably shouldn’t have leaned on it as the main motivation.
If there’s anything left worth salvaging here, it’s narrower than “change the syntax”: something like being able to visually align a column of declarations by type when skimming a file with many annotations (which type: name makes trivial and name: type doesn’t, since names have irregular lengths). But that’s a formatting/tooling preference, not a language-level readability argument, and PEP 20 is a real cost against introducing a second way to write the same thing for that benefit alone.
Given that, and given the grammar issue [name] raised in the other reply, I think this is more honestly a “nice to have in a formatter someday” than a language change. Appreciate the pushback — it’s the right call.
This is the point that actually breaks the proposal, and I don’t think there’s a clean fix for it. You’ve identified exactly why: int, str, object, etc. aren’t keywords in Python, they’re just regular names bound to builtin type objects at module/builtins scope, and they can be reassigned, shadowed, or used as ordinary values. So the parser has no way — at parse time, before any name resolution — to know whether int: object = 42 means “annotate object as type int” (my proposal) or “annotate int as type object” (existing PEP 526 syntax). Both are syntactically identical strings under the current grammar, and disambiguating would require either:
reserving all builtin type names as keywords (which would break an enormous amount of existing code that shadows names like type, list, id, object, etc.), or
inventing new syntax (a sigil, a keyword prefix) to mark the type-first form — at which point it’s no longer the clean drop-in alternative I was proposing, it’s a different and uglier construct that has to coexist with PEP 526 forever.
Neither of those is worth doing for a purely cosmetic reordering. I think this settles it — thanks for stating it this precisely, it’s clearer than how I was thinking about the grammar issue in my own post.
FYI, this is not the same thing. A type declaration isn’t for creating an object that has the type “TypeForm” or something like that. It’s for telling the type checker about a type alias. That’s why it has different syntax than an ordinary variable annotation: it’s not an ordinary variable.
people also shouldn’t waste resources / use LLMs to generate initial proposals. bullet point 2 in the “Known problems” section is utter nonsense and anyone who uses the thing between the ears would have ditched the itch at that point.