On Sun, Dec 12, 2021 at 07:43:16PM -0800, Brendan Barnwell wrote: > The question is what does this annotate: > > Annotated[int, "some text here"]
Nothing. There's no annotation there. That's an expression which returns a type alias. It is just an object. You can print it, put it in a list, pass it to a function, use it as a dict key, or garbage collect it. Or even use it to annotate a variable, but isolated as show, it isn't annotating anything. An annotation is "A label associated with a variable, a class attribute or a function parameter or return value" and that expression above is not a label associated with anything. https://docs.python.org/3/glossary.html#term-annotation To be an annotation, it must be part of a parameter annotation, or variable assignment annotation: def func(param:expression) -> expression: variable: expression All three of those expressions could legitimately be called an annotation, even if they're not types. Here's an analogy: you know how dicts work, right? (Of course you do.) We agree that in the dict {"Hello world": 42} the string "Hello world" is the key associated with value 42. So in the context of that dict, "Hello world" is a key. # helloworld.py print("Hello world") Is that string "Hello world" a key in a dict now? What's its value? How about in isolation, "Hello world", with no implied context and most especially no dicts anywhere in sight. Is it still a key if there is no dict for it to be a key of? I'm not asking whether it *could* be a key, if there was a dict. Obviously the answer is yes. I'm asking, what dict is "Hello world" the key of in the helloworld.py program above. If we can understand that being a key describes the *role* of a string, in a specific context, and is not a property of the string itself, we should be able to understand that being an annotation is likewise descibing the *role* of an object, in a specific context, and is not a property of the object itself. types: "Hello world" = (int, float, Annotated[int, "..."], str) Here, "Hello world" is an annotation, and the Annotated type alias is a element of a tuple. Earlier the same string was the output of a program, and before that it was a key. But it's the same string. Annotated[int, "some text here"] can likewise be an annotation, or the output of a program, or a key in a dict, or an element of a tuple, depending on context. With no context, it is just a type object. If its not part of an annotation statement or a function annotation, it's not an annotation. https://docs.python.org/3/glossary.html#term-function-annotation https://docs.python.org/3/reference/simple_stmts.html#annassign > In other words what does the use of Annotated in itself annotate. In itself, nothing. There's no annotation syntax in that expression. It's not a function annotation or a variable annotation. It doesn't create an `__annotations__` dunder. It meets none of the definitions of "annotation". > As Paul pointed out in his earlier message, you can create this > Annotated > thing without attaching it to any attribute. It seems that Annotated > itself is annotated the type. In fact, there can be no debate about > what Annotated annotates, since the documentation even says it > explicitly (https://docs.python.org/3/library/typing.html#typing.Annotated): > > > Specifically, a type T can be annotated with metadata x via the > typehint Annotated[T, x]. You are right about the first part of your sentence: there can be no debate about this. The doc is simply wrong, and it has confused you and others into thinking that Annotated[T, ...] has annotated T. But if anyone wants to debate it, if you think the documentation is correct, then it is easy to prove me wrong, and I will happily admit that I have learned something new. All you need to do is show me the annotation syntax `target: expression` in either of the following: # A bare expression, with no context. Annotated[int, "some text"] # A type alias. MyAlias = Annotated[int, "some text"] Easy peasy. Point to the annotation syntax colon to prove that I am wrong, and the docs are right. Or you can show me the `__annotated__` mapping with int as the key that either of those two lines create. But if you can't do any of those things, then: - there is no annotation syntax; - there is no "label associated with a variable, a class attribute or a function parameter or return value"; - there is no `__annotations__` dunder to hold that association; and therefore **there is no annotation**. It's just an expression returning a type. > The text specified in `Annotated[T, text]` is creating a sort of > augmented type The docs and the implementation call them Type Aliases. "Augmented" is an excellent description, thank you for suggesting it. So we can agree that Annotated[T, *metadata] returns a type alias, based on T, but augmented with the metadata. That is an excellent way to describe it, that avoids the confusion with annotations. Yes, the primary use-case of such a type alias is to use it in annotations, but its just an object, you can use it for many things. > which is like > "a type that is type T but additionally means such-and-such". It is > true that that can type can itself later be used to annotate an > attribute (or variable), but at that point it will be marking the > variable as being of a type that incorporates the annotating text, not > annotating the variable itself with that text. What you call "marking the variable" is what Python calls an annotation. And the meaning of annotations is **not specified by the language**. Typing is the primary use-case but it is not the only one. Any alternative use of annotations has to work with a widespread assumption that annotations will be types, but that is doable. > As such, I don't think Annotated is really a good choice for this. > We really want the text of the annotation to be associated with the > attribute itself, not with the attribute's type. Moreover, using > Annotated requires the user to specify a type, Which you can do with Any. That is hardly a major imposition for code that is already using typing, and for code that isn't using typing, you don't have to worry about it. Just use a string. > but people should be able > to specify annotations for documentation even if they're not using > typing at all and not specifying any types. (They shouldn't have to > resort to an awkward workaround like always throwing in a dummy Any type.) And they can do that to, just by *not using a type checker*. @no_type_checking class C: attr: "Doc string" Done. The doc string is recorded in the __annotations__ dunder, but you can post process it any way you like. If you want a *standard* mechanism that will be blessed by the language, then it has to interoperate with typing. We've already had the idea of following the variable with a bare string rejected: https://www.python.org/dev/peps/pep-0224/ and I see no reason to think that the situation has changed in any way since then. But if you want to propose re-opening PEP 224 and having another go at it, be my guest. > As an aside, seeing what the docs say about Annotated makes me think > that "Annotated" is a very bad name for this thing. It confuses the > idea of a type annotation (i.e., attached to a variable) with this > type-incorporating-a-label, where neither the label nor the type is > actually an annotation in the type-annotation sense (because they have > not been attached to a variable to annotate it). Right! > It seems it would have > been better to called Annotated "Tagged" or "Labeled" or some such thing > to make it clear that when you using it you are defining a new > special-purpose type for use in later annotations./ Indeed. -- Steve _______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/EDAYOO4HEJUNL7J2L4ZFWQXQDGFJKT7T/ Code of Conduct: http://python.org/psf/codeofconduct/