-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Specializing generic class over ParamSpec #15096
Comments
I realized, instead of trying to pass an existing function, I could also pass a However, there are still two bugs in mypy which block me from achieving my goal or testing any further:
|
Functions cannot be used as type arguments to a generic class in the current Python static type system, so "Attempt 1" will not work. "Attempt 2" doesn't look like it will work at runtime, at least not as it's currently implemented, because I don't see anything else actionable in the bug report, so I think it can be closed. |
This change provides the correct function signatures for __call__() and si() in the network classes. This enables typechecking the uses / calling locations of the networks in the rest of the code. It immediately uncovered a bug in PerfectInformationRLPlayer.own_move(), where the representation network was called with an additional None argument before the observations. This is a remnant from the time with beliefs in the representation network. It did not do any harm because None inputs are filtered out in the fully connected networks. Previously: - forward() had the correct signature, but that is never called in the code, only overridden by network implementations - __call__()'s signature came from nn.Module, where it has Any for arguments and return value - si() came from NetworkBase, where I could only customize the return type An ideal solution would be to have base class which is generic over function signatures, so the code can be reused. I was not able to get that to work in mypy tho: python/mypy#15096 So, therefore a lot of duplicate code in each of the abstract base classes.
Bug Report
I tried to be too clever and wanted to feed the signature of an existing function in a generic class. The goal is to specialize the class for different signatures.*
I invested quite some time trying, but It always failed in funny ways.
I realize that this is probably not intended to work, but I could not find any information in the mypy / python typing docs which explicitly forbids this. I am therefore not sure if this is a mypy or documentation issue.
I want to share my results here. Maybe they are useful as a test scenario or for discovering bugs.
To Reproduce
Common setup, shared with all examples:
Attempt 1: Custom generic class (playground)
Attempt 2: Class decorator (playground)
Expected Behavior
No errors, inheritance from the specialized Protocol.
See also the lines with
# works
comments.Additional comments
*I am aware of some alternatives:
My current workaround, using a hand-written class specialized for every signature I want to use. I write one method and copy the signature over to the others.
The problem is, I have to repeat this for every method in every class instead of just specializing the generic class multiple times.
TypeVarTuple
/ParamSpec
with a tuple of argument types:This unfortunately does not capture positional argument names
My use case is related to PyTorch: Modules implement a
forward()
method, but are called using a superclass's__call__()
, which does not know anything about theforward()
's signature. I want to write an abstract base class that:forward()
__call__()
to typecheck the usage outside of the moduleforward()
's signatureYour Environment
The text was updated successfully, but these errors were encountered: