Re: Property type hints?
On 10/12/2020 13:06, Paul Bryan wrote: 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. I'm a great fan of them too - the saving of 'boilerplate code' does it for me; but yes, the typing benefits come for-free! Just in case it needs to be said: there's no need to 'declare' properties (or any other methods) as if they are class-attributes - either when using data-classes or rolling-your-own! Also, remember that class-attributes will become (actually be 'hidden' by) instance-attributes if used on the LHS of an expression within the class (replicating the 'two' entity problem, discussed earlier). -- Regards =dn -- https://mail.python.org/mailman/listinfo/python-list
Re: Property type hints?
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': } > >>> > > 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': } > >>> > > 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': } > > > > 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': } > > 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': } > > 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': } > > 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
Re: Property type hints?
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': } >>> 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': } >>> 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': } 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': } 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': } 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': } 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
Property type hints?
Would this be a reasonably correct way to annotate a property with a type hint? >>> class Foo: ... bar: int ... @property ... def bar(self): ... return 1 ... >>> foo = Foo() >>> import typing >>> typing.get_type_hints(foo) {'bar': } I could also decorate the property method return value: ... def bar(self) -> int: I don't see the point though, because you can't access it with get_type_hints. -- https://mail.python.org/mailman/listinfo/python-list