0

I have the following setup:

T = TypeVar("T")


@dataclass
class Type(Generic[T]):
    name: str
    data: T


@dataclass
class Aspect:
    name: str
    from: Type[str]
    to: Type[int]
    func: Callable[[Type[str]], Type[int]]

This works great, but I've tied my Callable to str and int, and I would want something even more generic like being able to define func as something like:

func: Callable[[Type[A]], Type[B]]

where A and B can be whatever, so I can define and send a func like (a: Type[str]) -> Type[int]:... or (a: Type[float]) -> Type[str]:... or whatever

Right now I can have a function:

def func1(a: Type[str]) -> Type[int]:
    return Type("func1", 1)

which I can use to create an Aspect Aspect("asp1", type1, type2, func1)

But I can't create an Aspect in the same way with a function like:

def func2(a: Type[int]) -> Type[str]:
    return Type("func2", "2")

and then call Aspect("asp1", type1, type2, func2)

I've tried creating different TypeVars to use in the callable, but it doesn't work, mypy says they are unbound, I've also tried to work around this with ABC but to no success, is there any way to express this?

3
  • I'm not sure if that's what you mean, but if you want to genericize those parameters as well you need to make those generic parameters of Aspect. Alternatively, if you don't care about type safety then make it Type[Any]. Commented Aug 26, 2022 at 12:04
  • I mean right now the only functions I can use for Aspect must have the Type[str] -> Type[int]. ``` def func1(a: Type[str]) -> Type[int]: return Type("func1", 1) ``` but I might want an Aspect with a different function like: ``` def func2(a: Type[float]) -> Type[str]: return Type("func2", "2") ``` and right now with the Callable definition I can't do that. Commented Aug 26, 2022 at 12:06
  • If you are completely new to the concept of generics I'd recommend not doing them in Python first. They are quite obscure and imo ill done in Python. Read about them in a Java or C# tutorial. They are easier to grasp in statically typed languages. Commented Aug 26, 2022 at 12:25

1 Answer 1

1

Generics allow you to bind a generic type T, A, or B to a concrete type within a class or function. In your case you want every instance of A and B represent the same type across the entire class, therefore you must bind A and B inside a class by extending Generic[A, B].

T = TypeVar('T')
A = TypeVar('A')
B = TypeVar('B')


@dataclass
class MyType(Generic[T]):
  name: str
  data: T


@dataclass
class Aspect(Generic[A, B]):
  name: str
  from_: MyType[A]
  to: MyType[B]
  func: Callable[[MyType[A]], MyType[B]]

(changed Type to MyType to avoid confusion with typing.Type) It essentially tells python: "Let's define A and B to mean the same thing across the class"

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you, I didn't think of extending from Generic(A, B), though I did use the type vars A and B.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.