-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
How do I type a generic factory function? #6073
Comments
This is not really mypy's problem. This just doesn't work at runtime. From mypy perspective it is totally fine. For example, as you can see in your initial version of the code: s, r = open_channel_pair[str](0) # Type application is only supported for generic classes
reveal_type(s) # Revealed type is 'SendChannel[builtins.str*]'
reveal_type(r) # Revealed type is 'ReceiveChannel[builtins.str*]' the first error is bogus, because it is actually supported in mypy, just not at runtime. I think we should just remove this error, so that one can at least use Later we can support a safer version of cast for such cases (we already discussed this), or you can try discussion whether this can be allowed at runtime on CPython forums (a trivial
What is wrong with this type? It looks totally fine to me. |
It seems like this might need an update to PEP 484? And ideally some more details on exactly what the semantics are :-).
It's also easy to hack a class generic_function:
def __init__(self, fn):
self._fn = fn
def __call__(self, *args, **kwargs):
return self._fn(*args, **kwargs)
def __getitem__(self, _):
return self
@generic_function
def open_channel_pair(...):
... ...except that then I can't figure out how to type I tried the blunt hammer of
and both revealed types are
It's not... type syntax? Like I can definitely not write I guess in PEP 484 it is normal that you can't point to a function and say "what's the type of this?" (e.g., anything with keyword arguments also has an inexpressible type). It's just not what what other type systems have trained me to expect. |
I found another way to write this that works: class open_channel_pair_type:
def __call__(self, buffer_size: int) -> Tuple[SendChannel[Any], ReceiveChannel[Any]]:
# ... insert real implementation here ...
return (SendChannel(), ReceiveChannel())
def __getitem__(self, _: Type[T]) -> Callable[[int], Tuple[SendChannel[T], ReceiveChannel[T]]]:
return self
open_channel_pair = open_channel_pair_type() I guess this is less gross than abusing |
The syntax of
Requiring a decorator on every generic function is a big change. We can of course clearly document that it is optional, and is only required if one wants to subscript the function. In any case, I think this requires a wider discussion. |
Oh yeah, I just meant to use it on that subset of generic functions where you explicitly specify the type when calling. Not sure if there's a name for that. Is there a better place to have this discussion for people to see it, or...? |
Typing-sig?
On Tue, Dec 18, 2018 at 6:26 PM Nathaniel J. Smith ***@***.***> wrote:
Requiring a decorator on every generic function is a big change. We can of
course clearly document that it is optional, and is only required if one
wants to subscript the function. In any case, I think this requires a wider
discussion.
Oh yeah, I just meant to use it on that subset of generic functions where
you explicitly specify the type when calling. Not sure if there's a name
for that.
Is there a better place to have this discussion for people to see it,
or...?
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#6073 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/ACwrMuV-BKNUs4r2bWxJl_4xfT52BtY7ks5u6aPdgaJpZM4ZUiwa>
.
--
--Guido (mobile)
|
@njsmith 's most recent suggestion doesn't work for "special forms", because they can't be inferred as the
shows that int and List[int] work, but the tuple and callable forms don't.
|
@oremanj Oh, that is a subtle flaw indeed, nice catch. I just tried it, and it looks like my original version (the @ilevkivskyi's trick of simply writing Probably someone should start a discussion about this on typing-sig, basically suggesting making the |
Closing this issue since the consensus seems to be that this should be discussed on typing-sig@. |
[Not sure if this is the right place to file issues like this, feel free to tell me to go somewhere else :-)]
I have two generic types:
I have a factory function that creates a linked pair of these objects:
I would like to allow people to call it like:
This works for the factory callables built into the language, e.g. calling
SendChannel[str]()
returns an object of typeSendChannel[str]
. This is basically the same thing, but since I have to construct two objects in a single operation, the regular thing doesn't work.I did come up with a sneaky hack:
This is gross, though. Is there any way to define a regular callable that has the same type as a generic class constructor, but is less gross than this?
What even is the type of a generic class constructor?
reveal_type(SendChannel)
printsdef [T] () -> SendChannel[T`1]
, which is a very strange looking type.The text was updated successfully, but these errors were encountered: