The high-level question is above my pay grade, but just to note, if this was done it presumably wouldn’t be as a keyword but as a built-in constant like None, ..., True and False. Making it reassignable, like NotImplemented but unlike the former examples, shouldn’t break essentially any existing working code (with a very few corner-case exceptions that try-except for whether Any is defined). However, this would be the first time a typing-only construct is exposed as a built-in outside the typing standard library module, so there might be resistance on that grounds.
@Jelle , you might be interested in responding to this.
Good point. I’ll refrain from editing the original to avoid making the thread confusing, but I should have been suggesting it as a builtin, not a keyword. I thought of keywords because all new keywords have been soft (e.g. match), and I couldn’t think of a builtin which can be redefined. NotImplemented is a good example.
Yes, and I can understand the fears about beginners writing x = Any and getting confused…
Still, Any is uniquely prevalent in annotations. I can’t help but feel like it would be nice to always have access to it.
Pulling typing that far into the language is not a step we have taken yet. If type checkers assume from typing import * and you use from __future__ import annotations then having it as a built-in isn’t quite so critical.
There may be concerns about confusion between the any() builtin and Any.
While Any is common in type annotations, ideally it shouldn’t be, because we’d rather have more precise types. So maybe it’s good to make it a bit harder to reach for Any compared to more precise types.
By Jelle Zijlstra via Discussions on Python.org at 29Mar2022 23:16:
While Any is common in type annotations, ideally it shouldn’t be,
because we’d rather have more precise types. So maybe it’s good to make
it a bit harder to reach for Any compared to more precise types.
That was my immediate gut concern: making it easier to effectively make
things nearly untyped. Surely if you’re type annotating your code, this
is the least valueable name to make available for free.
def is_empty_sequence(x: Sequence[Any]) -> bool:
return not len(x)
Some of this is informed by which type checker you use and even which flags you set. mypy --strict enforces list[Any] over list, and def f(x: Any) over def f(x).
So by rolling out mypy --strict on codebases that do a bunch of serialization and deserialization of data, I’m probably “asking for more Anys”.
Both of these examples would work even if you used object instead of Any.
I think there are lots of places where people use Any unnecessarily like this and don’t realize that object is a valid annotation, and should be used when your code really accepts literally “any” object.
And it is already built-in.
Any is for the rare cases when you don’t really want to say “any object”, but writing down the precise type is impossible or too cumbersome.
So it is fine to leave Any in typing,since it should be rarely used over object.
And the Any vs object distinction should be clarified more, maybe in the docs for typing.Any (and use of object should be encouraged more).
In the examples above, I was trying to keep it brief, maybe too brief. We can construct cases where object doesn’t work, but it’s likely to take this thread off-topic.
Perhaps object should be encouraged more, but I’m not fully convinced. The difference is subtle enough that I’d be concerned giving that advice to new users of type annotations.
If the docs were to start recommending object more strongly, they would also need to explain more about when to use one vs the other.
data = json.load(stream)
if not isinstance(data, dict): raise ValueError("boo")
typed_data = cast(dict[str, object], data) # uh-oh!
return typed_data["foo"]["bar"] # fails
except LookupError as e:
raise ValueError("sorry") from e
Sure, but I view that change as motivated by typing, but not only for typing; there are at least other potential use-cases for that functionality. An Any built-in is a bit harder to motivate for anything but typing.
In this case the part that fails doesn’t work for all objects, so the point about object doesn’t apply. object doesn’t work as a replacement for Any everywhere, only in cases where you really meant “any object”.
That line works only for some types of objects which allow __getitem__ with a str which in turn returns another object that allows __getitem__ with an int. That could be a Protocol or a TypedDict or just dict[str, dict[str, list[object]]
So this is the case where you use Any because you don’t know how to define the precise type and think it is impossible (or you just want to be lazy and feel defining TypedDict or Protocol is too cumbersome).
Ideally these cases should be avoided, and I think maybe giving easy access to Any as built-in would encourage it more.
I’m surprised at this, I personally use Iterable, Sequence, Generator, Callable, Mapping, … all more often than Any. Is there something I’m missing to suggest the usage of these other types from typing are less common, or being replaced with something that doesn’t require an import from typing (hopefully not just being replaced with Any!)?
Of the symbols in typing, the only ones I considered suggesting were Any and Final. There are plenty of other useful names there, but I’m looking at the ones which I think will have the greatest potential positive impact on the language with the smallest possible change.
Final is often omitted from code where it could, and arguably should, be used simply because nobody bothered to import it.
Many modules can’t be annotated without importing typing. When I look at those which only import a single value from typing, it tends to be Any more often than any other.
All that said, it currently seems that the support for this idea is weaker than the concerns about it.
I’m going to come out as a strong -1 for sneaking anything typing-related (even Any) into builtins. Python looks to me more and more like a language with type declarations as a builtin part of the language. It’s beauty has always been its simplicity. Such is, I’m afraid, not the case anymore. I believe it was Fredrik Lundh who opined that as a language Python reached its zenith in 1.5.2. That’s surely a debatable proposition, but I’m sure the Effbot wouldn’t be happy with “optional” type declarations at all.
I know I don’t count, but I thought someone had to lone voice in the wilderness on this one.
I would say you’re hardly a lone voice. I (and others on typing-sig) are sensitive to the desire to avoid typing-related features & annotations complicating the rest of Python by default, despite me personally being an advocate of typing for large codebases.