0

This works:

from typing import Union, Callable

class Ordinal:
  def __init__(self, children : Union[None, 'Ordinal']):
    self.children = children

This doesn't:

from typing import Union, Callable

class Ordinal:
  def __init__(self, children : None | 'Ordinal'):
    self.children = children

# TypeError: unsupported operand type(s) for |: 'NoneType' and 'str'

I'm fine using the first one, but would like to know what's going on here, so I make sure the first one isn't actually just implementing something entirely different.

(for clarity, I'm defining the type Ordinal recursively with stringized annotations.)

  • 1
    Check your Python version. Using `|` to union types is relatively new. – Samwise Jun 06 '23 at 16:08
  • @Samwise The version's 3.10.11, and it works fine if I replace the `'Ordinal'` with any type other than a stringized annotation -- even `Callable[[int], 'Ordinal']`. – Abhimanyu Pallavi Sudhir Jun 06 '23 at 16:10
  • 1
    Are you looking for `from __future__ import annotations`‽ – deceze Jun 06 '23 at 16:14
  • @deceze Wait that actually worked, thanks, but I don't understand the magic trick. – Abhimanyu Pallavi Sudhir Jun 06 '23 at 16:17
  • `|` isn't overloaded to handle `str` arguments; the `__future__` import disables runtime evaluation of type hints, so the definition of `|` doesn't matter. – chepner Jun 06 '23 at 17:23
  • @chepner Wait, it disables evaluation of type hints? Isn't that bad? – Abhimanyu Pallavi Sudhir Jun 06 '23 at 17:32
  • It "disables" the evaluation of the annotation expression and just takes it as a string as is. That string can later be evaluated by type checking tools as needed. You could always do this by writing strings as annotations, the future import just makes it implicitly so always, which is/should/will be the default behaviour eventually. See the duplicate linked above. – deceze Jun 06 '23 at 17:36
  • Evaluation of type hints is what Python will do at runtime. It's separate from a static analyzer like `mypy`, which does not execute any code, from using them to perform type checking. – chepner Jun 07 '23 at 13:04
  • To be clear, `mypy` itself is fine with `None | 'Ordinal'`; it's Python that can't evaluate it. (Function annotations are arbitrary expression, though expressions not consistent with the semantics defined by PEP 484 are deprecated.) – chepner Jun 07 '23 at 13:06

0 Answers0