Re: Property type hints?

2020-12-09 Thread dn via Python-list

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?

2020-12-09 Thread Paul Bryan
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?

2020-12-09 Thread dn via Python-list

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?

2020-12-08 Thread Paul Bryan
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