Way to define a generic tensor-like type (like tf.Tensor | torch.Tensor | np.ndarray | float) in python 3.8?
I'm annotating my code for a high level neural network library. I want to make it as flexible as possible while still clarifying type expectations for developers using the library. In many cases, this requires writing 'generic' functions that operate on tensors defined in arbitrary backends (like tf.Tensor, torch.Tensor, np.ndarray, as well as python types like float, int, and bool; it'd be nice if I could statically enforce dtype's as well, but that not my concern here) Is there a way to define a generic Tensor-like type in python 3.8?

After coding for a few hours, I began to see that you don't want to do this in most cases. Here's some reasons why:

it's not pythonic. &quot;Avoid the magical wand&quot; when it adds needless complexity
you'll have duck-typing issues like calling .size in torch but .shape in tf which results in a lot of if/elif/else structures.
you're going to be repeating yourself for a lot of generic-backend logic

I would recommend for other developers facing this prediciment to seriously ask themselves if they are willing to maintain a high level framework on two backends. You see, any time you want to perform an operation on the tensor (say transpose()), you have to ask if that operation has an identical signature in all supported backends. If not, you start ending up with huge swaths of repeated if/elif/else code and development productivity really starts to suffer. If willing to proceed, try using an existing library like keras.backend which has limited tensorflow and thaneo support, or write your own cross-framework tensor-framework abstract for us all to use. (And please post a comment if you made or found one)
In most cases however, it suffices to imitate the einops approach and simply define an arbitrary TypeVar like so:
Tensor = TypeVar('Tensor')

Also, CoPilot recommended this to me:
TensorType = type(None)

Then you can use this type var in your annotations as expected:
def iterate(self, a: Tensor, b: Tensor) -&gt; Tensor:
  c = self.neural_net(a)
  d = c + a - b
  return d / a

