I recommend taking this to typing-sig... On Mon, Nov 23, 2020 at 19:18 David Foster <davidfstr@gmail.com> wrote:
On 11/22/20 10:15 AM, Guido van Rossum wrote:
- We intentionally don't support things like `isinstance(x, List[str])` because that would require checking all the items with `isinstance(item, str)`, and that seems a speed trap. Reverting this decision would be hard work.
Aye. I imagine many folks would expect isinstance() to be "fast" and altering it to do recursive checks on its argument would lose its current O(1) time.
I imagine I *could* implement my own kind of isinstance() that would work on TypedDict values that would still be recognized by typecheckers. Say I write an implementation for the following method:
from typing import Optional, Type, TypeVar, TypedDict
TD = TypeVar(bound=TypedDict)
def try_cast(type: Type[TD], value: object) -> Optional[TD]: """Returns `value` if it can be parsed as a `type`, otherwise None.""" raise NotImplementedError()
Then I could use that method in a similar way as my earlier example to parse a value very concisely:
if (shape := try_cast(Shape, request.json)) is not None: draw_shape(shape) # is narrowed to Shape else: return HTTPResponse(status=400) # Bad Request
Going further, I could extend try_cast() to accept any (non-None) JSON-like value as the top-level object (not just TypedDicts):
from typing import Dict, List, Optional, Type, TypeVar, TypedDict, Union
TD = TypeVar('TD', bound=TypedDict) JsonValue = Union[ TD, Dict[str, 'OptionalJV'], List['OptionalJV'], Dict, # heterogeneous Dict List, # heterogeneous List float, int, # because json.loads may return an int when parsing a number str, bool, ] JV = TypeVar('JV', bound=JsonValue) OptionalJV = TypeVar('OptionalJV', bound=Union[JsonValue, None])
def try_cast(type: Type[JV], value: object) -> Optional[JV]: """Returns `value` if it can be parsed as a `type`, otherwise None.""" raise NotImplementedError()
Now, I'm not sure if mypy can handle that kind of recursive TypedDict definition :), but it *will* work at runtime.
I'll see about implementing a function like try_cast() as a separate package. This should be fun. :)
-- David Foster | Seattle, WA, USA Contributor to TypedDict support for mypy
-- --Guido (mobile)