Thanks for the comprehensive response, dn! I guess I'm influenced by data classes here, where the object's attribute type hints are represented by class variable annotations.
On Thu, 2020-12-10 at 07:49 +1300, dn via Python-list wrote: > On 09/12/2020 13:17, Paul Bryan wrote: > > Would this be a reasonably correct way to annotate a property with > > a > > type hint? > > > > > > > class Foo: > > ... bar: int > > > If we build a class with (only) the above two lines, Python's help > lookup offers the following documentation: > > <<< > Help on Foo in module __main__ object: > > class Foo(builtins.object) > | Data descriptors defined here: > | > | __dict__ > | dictionary for instance variables (if defined) > | > | __weakref__ > | list of weak references to the object (if defined) > | > | ---------------------------------------------------------------- > ------ > | Data and other attributes defined here: > | > | __annotations__ = {'bar': <class 'int'>} > >>> > > Note the last line identifying 'bar' as having integer-type. > > However, when we continue, by adding a property/lookup-method called > 'bar'. > > > ... @property > > ... def bar(self): > > ... return 1 > > > ...the help lookup becomes: > > <<< > class Foo(builtins.object) > | Readonly properties defined here: > | > | bar > | > | ---------------------------------------------------------------- > ------ > | Data descriptors defined here: > | > | __dict__ > | dictionary for instance variables (if defined) > | > | __weakref__ > | list of weak references to the object (if defined) > | > | ---------------------------------------------------------------- > ------ > | Data and other attributes defined here: > | > | __annotations__ = {'bar': <class 'int'>} > >>> > > Note that 'bar' has now been listed as a read-only property. > > Further, if we remove the explicit typing (int) of 'bar', the help > listing doesn't change. > > > <<< > class Foo(builtins.object) > | Readonly properties defined here: > | > | bar > | > | ---------------------------------------------------------------- > ------ > | Data descriptors defined here: > | > | __dict__ > | dictionary for instance variables (if defined) > | > | __weakref__ > | list of weak references to the object (if defined) > >>> > > Except that the annotation documentation has disappeared! > > Hence, one assumes, the question! > > The problem is that the help system appears to be talking about two > different things: 'bar' the class int, and 'bar' the method/property. > At > run-time however, there cannot be two uses of the same name, and the > last-defined 'wins'. > > Continuing:- > > > ... > > > > > foo = Foo() > > > > > import typing > > > > > typing.get_type_hints(foo) > > {'bar': <class 'int'>} > > > > I could also decorate the property method return value: > > ... def bar(self) -> int: > > ...and when the typing-hint is added to the property's def, the help > listing still doesn't change/improve. > > > That said, I've been following this last convention since moving to > typing. > > Putting a separate description at the beginning of the class invites > the > reader to think of 'foo' as an integer. That's not 'wrong', in the > sense > that a property is/produces an attribute in the same dotted-notation > from the object-name. However,there could be quite a lot of code > between > this 'declaration' line and the property def! > > However, there is another line of logic built upon the idea that all > class-attributes should be defined in the class 'header' and all > instance-attributes in __init__() or __post_init__(). Does this > underlie > the discussion? > > > > I don't see the point though, because you can't access it with > > get_type_hints. > > Correct: if one codes (only) the property-bar, then: > > >>> get_type_hints( Foo ) > {} > > However, reverting back to the first class-definition, we do see > something for our money: > > >>> get_type_hints( foo ) > {'bar': <class 'int'>} > > Unfortunately, as mentioned above, there is this confusion between > the > two 'bar's... > > Proof? > > If we change things, the result is not what (it would appear) is > desired: > > >>> class Foo: > ... bar:str > ... @property > ... def bar( self ): > ... return 1 > ... > >>> get_type_hints( Foo ) > {'bar': <class 'str'>} > > Yet the 'bar' property will return an int! > > ...and this is proven/made worse when we add explicit typing to the > property definition: > > >>> class Foo: > ... bar:str > ... @property > ... def bar( self )->int: > ... return 1 > ... > >>> get_type_hints( Foo ) > {'bar': <class 'str'>} > > Our documentation entries don't agree, and don't match 'reality'. > Ouch! > > Beyond that, I won't hazard a guess at the minds of the 'Python gods' > who design and implement these things. However, please remember that > in > this discussion we have been using Python itself, whereas the docs > and > PEP-justifications for typing clearly say: > > <<< > Note The Python runtime does not enforce function and variable type > annotations. They can be used by third party tools such as type > checkers, IDEs, linters, etc. > >>> > > which may stump whatever the aim in using get-type-hints() may have > been. > > > If we're only talking about code-review, then (personal) comment of > 'documenting' the method-definition applies. > -- > Regards =dn -- https://mail.python.org/mailman/listinfo/python-list