type annotation vs working code
Mats Wichmann
mats at wichmann.us
Sat Sep 30 15:34:52 EDT 2023
On 9/30/23 13:00, Karsten Hilbert via Python-list wrote:
> A type annotation isn't supposed to change what code does,
> or so I thought:
>
> #------------------------------------------------------------
> class Borg:
> _instances:dict = {}
>
> def __new__(cls, *args, **kargs):
> # look up subclass instance cache
> if Borg._instances.get(cls) is None:
> Borg._instances[cls] = object.__new__(cls)
> return Borg._instances[cls]
>
>
> class WorkingSingleton(Borg):
>
> def __init__(self):
> print(self.__class__.__name__, ':')
> try:
> self.already_initialized
> print('already initialized')
> return
>
> except AttributeError:
> print('initializing')
>
> self.already_initialized = True
> self.special_value = 42
>
>
> class FailingSingleton(Borg):
>
> def __init__(self):
> print(self.__class__.__name__, ':')
> try:
> self.already_initialized:bool
> print('already initialized')
> return
>
> except AttributeError:
> print('initializing')
>
> self.already_initialized = True
> self.special_value = 42
>
> s = WorkingSingleton()
> print(s.special_value)
>
> s = FailingSingleton()
> print(s.special_value)
>
> #------------------------------------------------------------
>
> Notice how Working* and Failing differ in the type annotation
> of self.already_initialized only.
What happens here is in the second case, the line is just recorded as a
variable annotation, and is not evaluated as a reference, as you're
expecting to happen, so it just goes right to the print call without
raising the exception. You could change your initializer like this:
def __init__(self):
print(self.__class__.__name__, ':')
self.already_initialized: bool
try:
self.already_initialized
print('already initialized')
return
The syntax description is here:
https://peps.python.org/pep-0526/#global-and-local-variable-annotations
More information about the Python-list
mailing list