Why not extend isInstance to :

isinstance(object:Any,classinfo: Iterable | Union) ?


Le ven. 30 août 2019 à 09:41, Dominik Vilsmeier <[email protected]>
a écrit :

> Andrew Barnert wrote:
> > On Aug 29, 2019, at 16:03, Dominik Vilsmeier [email protected]
> wrote:
> > > I never really understood the importance of
> > > Optional. Often it can be left out altogether and in other cases I find
> > > Union[T, None] more expressive (explicit) than Optional[T] (+
> > > the latter saves only 3 chars).
> > > Especially for people not familiar with typing, the meaning of
> Optional is
> > > not obvious at first sight. Union[T, None] on the other hand is pretty
> clear.
> > > Also in other cases, where the default (fallback) is different from
> None,
> > > you'd have to use Union anyway. For example a function that normally
> returns
> > > an object of type T but in some circumstances it cannot and then it
> returns
> > > the reason as a str, i.e. -> Union[T, str];
> > > Optional won't help here.
> > > But this should be very rare.
> > Most functions that can return a fallback value return a fallback value
> of the expected
> > return type. For example, a get(key, default) method will return the
> default param, and
> > the caller should pass in a default value of the type they’re expecting
> to look up. So,
> > this shouldn’t be get(key: KeyType, default: T) -> Union[ValueType, T],
> it should be
> > get(key: KeyType, default: ValueType) -> ValueType. Or maybe get(key:
> KeyType, default:
> > Optional[ValueType]=None) -> Optional[ValueType].
> > Most functions that want to explain why they failed do so by raising an
> exception, not
> > by returning a string.
> > And what other cases are there?
>
> Well, I actually made this up, so I can't think of any other real cases
> either :-)
>
> > Of course you could be trying to add type checking to some weird legacy
> codebase that
> > doesn’t do things Pythonically, so you have to use Union returns. But
> that’s specific to
> > that one weird codebase.
> > Meanwhile, Optional return values are common all over Python.
> > Also, Python’s typing system is a lot easier to grasp if you’re familiar
> with an
> > established modern-typed language (Swift, Scala, Haskell, F#, etc.), and
> they also use
> > Optional[T] (or optional<T> or Maybe t or some other spelling of the
> same idea) all
> > over be place—so often that many of them have added shortcuts like T? to
> make it easier to
> > write and less intrusive to read.
>
> I don't have experience in any of these languages (basically I'm
> self-taught Python), so I learned it mostly from the docs (also
> `Optional`). That doesn't necessarily imply understanding the importance of
> the concept, but I acknowledge that `Optional[T]` is much easier to read
> than `Union[T, None]`; the former has less visual overhead and it reads
> more like "natural" language, so once you combine this with the fact that
> functions return `None` when they don't hit a `return` statement (or the
> convention of explicitly putting `return None` at the end), the meaning of
> `Optional[T]` becomes more clear.
>
> > I think there may be a gap in the docs. They make perfect sense to
> someone with
> > experience in one of those languages, but a team that has nobody with
> that experience
> > might be a little lost. There’s a mile-high overview, a theory paper,
> and then basically
> > just reference docs that expect you to already know all the key concepts
> that you don’t
> > already know. Maybe that’s something that an outsider who’s trying to
> learn from the docs
> > plus trial and error could help improve?
> > > Scanning through the docs and PEP I can't find
> > > strongly motivating examples for Optional (over Union[T, None]).
> > > E.g. in the following:
> > > def lookup(self, name: str) -> Optional[Node]:
> > >        nodes = self.get(name)
> > >        if nodes:
> > >            return nodes[-1]
> > >        return None
> > > I would rather write Union[Node, None] because that's much more
> explicit
> > > about what happens.
> > > Then introducing ~T in place of Optional[T] just further
> > > obfuscates the meaning of the code:
> > > def lookup(self, name: str) -> ~Node:
> > > The ~ is easy to be missed (at least by human readers) and the meaning
> not
> > > obvious.
> > > That’s kind of funny, because I had to read your Union[Node, None] a
> couple times
> > before I realized you hadn’t written Union[Node, Node]. :)
>
> I had a similar thought when writing this, so I get the point. I'm not
> arguing against `Optional` I just think it's less self-explanatory than
> `Union[T, None]` when you see it for the first time and if you're not
> familiar with the concept in general. But that doesn't mean you shouldn't
> familiarize yourself with it :-)
>
> > I do dislike ~ for other reasons (but I already mentioned them, Guido
> isn’t convinced,
> > so… fine, I don’t hate it that much). But I don’t think ~ is easy to
> miss. It’s not like a
> > period or backtick that can be mistaken for grit on your screen; it’s
> more visible than
> > things like - that everyone expects to be able to pick out.
>
> As I mentioned in my other relpy to Guido, patterns like -341 are easily
> recognizable as a negative number (i.e. you won't miss the `-`) because our
> brains are accustomed to seeing it. ~Noun on the other hand is not
> something you're likely to encounter in everyday language and thus it is an
> unfamiliar pattern. Noun? on the other hand is easily recognizable.
> Regarding the meaning, `T?` should be pretty clear (read as "maybe T", i.e.
> maybe you hit a return statement with `T` and if not it's going to be
> `None` by default); for `~` on the other hand I'm not aware of any meaning
> in natural language. I did a bit of internet search for symbols
> representing "optional" but I couldn't find any (e.g. none of the icon
> websites I tried gave satisfying results, or any results at all). Also the
> guys over at ux.stackexchange seem to agree that the only way to mark
> something optional is to write "optional" (
> https://ux.stackexchange.com/q/102930, https://ux.stackexchange.com/q/9684).
> Python code reads very natural, but I'm not convinced `~` would add to
> that; it's rather a step away.
> Personally, for me that's not important, I'm more of the style "look-up
> the docs and learn from there" rather than relying on my intuition of the
> meaning of something. But from other discussions on this list I had the
> impression that Python wants to keep possible confusions to a minimum,
> especially for newcomers (I remember the discussion about `while ...
> except` , with the main argument against, that this syntax could easily be
> confused). With `~` there probably won't be a confusion in that sense, but
> someone reading it for the first time will definitely need to look it up
> (which is fine i.m.o.).
>
> > > For Union on the other hand it would be
> > > more helpful to have a shorter syntax, int | str seems pretty clear,
> but what
> > > prevents tuples (int, str) from being interpreted as unions by type
> checkers.
> > > This doesn't require any changes to the built-in types and it is
> aligned with the already
> > > existing syntax for checking multiple types with isinstance or
> > > issubclass: isinstance(x, (int, str)). Having used this a couple
> > > of times, whenever I see a tuple of types I immediately think of them
> as or
> > > options.
> > > The biggest problem with tuple is that in every other language with a
> similar
> > type system, (int, str) means Tuple[int, str].
> > I think {int, str}, which someone proposed in one of the earlier
> discussions, is nice.
> > What else would a set of types mean (unless you’re doing mathematical
> type theory rather
> > than programming language typing)? But it’s unfortunate that things like
> isinstance and
> > except take a tuple of types (and it has to be a tuple, not any other
> kind of iterable),
> > so a set might be just as confusing for hardcore Python types as a tuple
> would be for
> > polyglots.
>
> The possible confusion with `Tuple[x, y]` is a strong counter-argument,
> but as you mention, `{int, str}` doesn't have this particular problem. The
> unfortunate part about `isinstance` is that it takes _only_ a tuple and not
> any kind of collection of types.
>
> > If the compatibility issue isn’t a big deal (and I trust Guido that is
> isn’t), I think
> > int | str is the best option. It’a an operator that means union, it’s
> used for sum/union
> > types in other languages, it makes perfect sense if you read it as “int
> or str”… I cant
> > imagine anyone being confused or put off by it.
>
> I also like the `int | str` syntax, and I can't imagine that it will cause
> any kind of confusion. One difference about `int | str` and `{int, str}`
> however is that successfully interpreting the meaning of the ` | ` syntax
> likely requires a context while for the `{ }` syntax it is clear that it
> defers the interpretation to whatever context it is used in. For example:
>
>     def foo(x: int | str):
>     def foo(x: {int, str}):
>
> Here it's pretty clear that both versions indicate multiple type options.
>
> However when reading something like:
>
>     x = int | str
>
> it's not immediately clear what this means and what `x` actually is (or
> represents). Probably `x` is used in type annotations later on but someone
> reading this statement (and maybe being unfamiliar with typing) could also
> assume something of the following:
>
> 1. Some kind of type chain with fallbacks, so that you can do `x(2.0) ==
> 2` with a fallback on `str`: `x('foo') == 'foo'`.
> 2. (shell style) Some kind of compound type, piping the output from `int`
> to `str`: `x(2.3) == str(int(2.3)) == '2'`.
>
> Only if you're familiar with `__or__`'ing types or you see this in a
> typing context it becomes clear that this means a type union.
>
> On the other hand `{int, str}` is just a collection of types, nothing
> more, no further meaning attached to it. Whatever meaning is eventually
> assigned to such a type collection is deferred to the context that uses it,
> e.g. type annotations or usage with `isinstance`. Similar for `x = (int,
> str)`, this can be used as `ininstance(foo, x)` or `type_chain(foo, x)` or
> `type_pipe(foo, x)`. Here it's the functions that give meaning to the type
> collection, not the collection itself.
> _______________________________________________
> Python-ideas mailing list -- [email protected]
> To unsubscribe send an email to [email protected]
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/[email protected]/message/OFH5DB6UMWVKJEK56K3YXZLHZY2ZIFSG/
> Code of Conduct: http://python.org/psf/codeofconduct/
>
_______________________________________________
Python-ideas mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-ideas.python.org/
Message archived at 
https://mail.python.org/archives/list/[email protected]/message/6BPCT2VNBUC4KXXFXAUKFZH5H353WWJT/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to