Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

New union shorthand giving "unsupported operand type(s) for |: 'str' and 'type'"

Before 3.10, I was using Union to create union parameter annotations:

from typing import Union

class Vector:
    def __mul__(self, other: Union["Vector", float]):
        pass

Now, when I use the new union shorthand syntax:

class Vector:
    def __mul__(self, other: "Vector" | float):
        pass

I get the error:

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

Is this not supported?

like image 913
rencedm112 Avatar asked Aug 30 '25 15:08

rencedm112


1 Answers

The fact that it's being used as a type hint doesn't really matter; fundamentally the expression "Vector" | float is a type error because strings don't support the | operator, they don't implement __or__. To get this passing, you have three options:

  1. Defer evaluation (see PEP 563):

    from __future__ import annotations
    
    class Vector:
        def __mul__(self, other: Vector | float): ...
    
  2. Make the whole type a string (effectively the same as deferring evaluation):

    class Vector:
        def __mul__(self, other: "Vector | float"): ...
    
  3. Keep using the Union:

    from typing import Union
    
    class Vector:
        def __mul__(self, other: Union["Vector", float]): ...
    

You can see further discussion on this bug, resolved by documenting the behaviour explicitly:

Note: The | operand cannot be used at runtime to define unions where one or more members is a forward reference. For example, int | "Foo", where "Foo" is a reference to a class not yet defined, will fail at runtime. For unions which include forward references, present the whole expression as a string, e.g. "int | Foo".

like image 102
jonrsharpe Avatar answered Sep 13 '25 14:09

jonrsharpe