I agree, that's duck typing with a protocol, and precisely the tedious type style I would want to avoid.
I don't know what would be a good suggestion. Something where you reference a "fully equipped" type and cherry pick the attributes you want? Something like `Protocol[Duck, ("quack", "waddle")]`? Paul On Wed, 2021-04-21 at 16:13 -0700, Jelle Zijlstra wrote: > > > El mié, 21 abr 2021 a las 15:30, Paul Bryan (<pbr...@anode.ca>) > escribió: > > As demonstrated, protocols don't get us there because duck typing > > isn't a matter of having an object exhibit all of the attributes of > > a duck, but rather some subset of attributes to be used by the > > consumer. I want this duck to quack; someone else will want it to > > waddle. I don't see how type hints could reasonably support "file > > like object" in the duck type sense (unless the consumer were to > > specify the exact attributes of the duck it's interested in, which > > I fear would become a tedious type writing style). ' > > > > > This approach (a Protocol that declares exactly what you need the > file-like object to do) is in fact what we've been doing in typeshed, > the repository that provides type hints for the standard library. For > those unfamiliar, it would look something like this: > > from typing import Protocol > > class SupportsRead(Protocol): > def read(self) -> bytes: ... > > def uses_a_file(f: SupportsRead) -> None: > f.read() > > That's somewhat tedious, to be sure, but it is working duck typing. > > > > > I too have sensed static typing driving the typing development > > agenda in Python recently, causing other typing methods to take a > > back seat, so to speak. I add my voice to those requesting Python > > handle other typing methods. > > > > Barring an innovation to allow a "subset" of a type to be declared > > in a type hint, I would conclude that static typing and duck typing > > are diametrically opposed. If we agree that both are valuable, > > developers could build consensus on that point, and work to ensure > > that one does not move forward at the expense of the other. > > > > What would you suggest? Should the syntax for declaring Protocols be > more concise? > > > > > Paul > > > > On Wed, 2021-04-21 at 12:36 -0700, Christopher Barker wrote: > > > Thanks Mark for posting this. I know some of us are uneasy about > > > the pace of the typing train .... > > > > > > On Tue, Apr 20, 2021 at 11:20 AM Nathaniel Smith <n...@pobox.com> > > > wrote: > > > > > If you guarded your code with `isinstance(foo, Sequence)` > > > > then I could > > > > > not use it with my `Foo` even if my `Foo` quacked like a > > > > sequence. I was > > > > > forced to use nominal typing; inheriting from Sequence, or > > > > explicitly > > > > > registering as a Sequence. > > > > > > > > You say this like it's a bad thing, but how is this avoidable, > > > > even in > > > > principle? Structural typing lets you check whether Foo is > > > > duck-shaped > > > > -- has appropriate attribute names, etc. But quacking like a > > > > duck is > > > > harder: you also have to implement the Sequence behavioral > > > > contract, > > > > and realistically the only way to know that is if the author of > > > > Foo > > > > tells you. > > > > > > > > > > > > > But that's not what duck typing is (at least to me :-) ) For a > > > given function, I need the passed in object to quack (and yes, I > > > need that quack to sound like a duck) -- but I usually don't care > > > whether that object waddles like a duck. > > > > > > So yes, isinstance(obj, Sequence) is really the only way to know > > > that obj is a Sequence in every important way -- but if you only > > > need it to do one or two things like a Sequence, then you don't > > > care. > > > > > > And this is not uncommon -- I suspect it's very rare for a single > > > function to use most of the methods of a given ABC (or protocol, > > > or whatever). > > > > > > And a lot of the standard library works exactly this way. Two > > > examples (chosen arbitrarily, I just happen to have thought about > > > how they work): > > > > > > json.load() simply calls ``fp.read()``, and passes the result on > > > down to json.loads(). That's it -- no checking of anything. > > > > > > If fp does not have a read() method, you get an AttributeError. > > > If fp has a read() method, but it returns something other than a > > > string, then you get some other Exception. And if it returns a > > > string, but that string isn't valid JSON, you get yet another > > > kind of error. > > > > > > In short, json.load(fp, ...) requires fp to have a read() method > > > that returns a valid JSON string. But it doesn't check, nor does > > > it need to, if it's getting an actual io.TextIOBase object. Is > > > that the right one? I'm not totally sure, which I kind of think > > > makes my point -- I've been using "file-like" objects for years > > > (decades) without worrying about it. > > > > > > Example 2: > > > > > > The str.translate method takes: > > > > > > "a mapping of Unicode ordinals to Unicode ordinals, strings, or > > > None" > > > > > > Ok, then you need to pass in a Mapping, yes? Well, no you don't. > > > The docs go on to say: > > > > > > The table must implement lookup/indexing via __getitem__, for > > > instance a > > > dictionary or list. > > > > > > Ah -- so we don't need a Mapping -- we need anything indexable by > > > an integer that contains "ordinals, strings, or None". What the > > > heck ABC could we use for that? > > > > > > The ABCs do have an already complex hierarchy of containers, but > > > there is no "Indexable", (quacks) and certainly no "indexable and > > > returns these particular things. (quacks a certain way). (maybe > > > there's something in the typing module that would work for static > > > typing -- I have no idea). > > > > > > I'm pretty sure this particular API was designed to accommodate > > > the old py2 str.translate, which took a length-256 sequence, > > > while also accommodating full Unicode, which would have required > > > a 2^32 length sequence to do the same thing :-) > > > > > > But again -- this is duck typing, built into the stdlib, and it > > > works just fine. > > > > > > Granted, until PEP 563 (kind of) , there has been nothing that > > > weakens or disallows such duck typing -- those of us that want to > > > write fully duck-typed code can continue to do so. > > > > > > But there is the "culture" of Python -- and it has been very much > > > shifting toward more typing -- A recent publication (sorry can't > > > find it now -- my google fu is failing me) examined code on PyPi > > > and found a lot of type hints -- many of which were apparently > > > not being used with a static type checker. So why were they > > > there? > > > > > > And I've seen a lot more isinstance(Some_ABC) code lately as > > > well. > > > > > > From looking at the work of my beginning students, I can tell > > > that they are seeing examples out there that use more typing, to > > > the point that they think it's a best practice (or maybe even > > > required?). Maybe it is -- but if the community is moving that > > > way, we should be honest about it. > > > > > > > I'm not even sure that this *is* nominal typing. You could just > > > > as > > > > well argue that "the operation `isinstance(..., Sequence)` > > > > returns > > > > `True`" is just another of the behavioral constraints that are > > > > required to quack like a sequence. > > > > > > > > > > > > > I'm not sure of the definition of "nominal" typing -- but it > > > absolutely is NOT duck typing (As Luciano pointed out, Alex > > > Martelli coined the term Goose Typing for this). > > > > > > The big distinction is whether we want to know if the object is a > > > duck, or if we only need it to do one or two things like a duck. > > > > > > -CHB > > > > > > > > > _______________________________________________ > > > Python-Dev mailing list -- python-dev@python.org > > > To unsubscribe send an email to python-dev-le...@python.org > > > https://mail.python.org/mailman3/lists/python-dev.python.org/ > > > Message archived at > > > > > > https://mail.python.org/archives/list/python-dev@python.org/message/ZXI3RTBVW44WGX44D4OFSH6GXL3SYPVO/ > > > Code of Conduct: http://python.org/psf/codeofconduct/ > > > > > > _______________________________________________ > > Python-Dev mailing list -- python-dev@python.org > > To unsubscribe send an email to python-dev-le...@python.org > > https://mail.python.org/mailman3/lists/python-dev.python.org/ > > Message archived at > > > https://mail.python.org/archives/list/python-dev@python.org/message/PDW6UUK2QFS3J6B6SIQGUE2E7J7IELIS/ > > Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ Python-Dev mailing list -- python-dev@python.org To unsubscribe send an email to python-dev-le...@python.org https://mail.python.org/mailman3/lists/python-dev.python.org/ Message archived at https://mail.python.org/archives/list/python-dev@python.org/message/HY6XET253F6XCSZGPNXESYL3KPOUXI6E/ Code of Conduct: http://python.org/psf/codeofconduct/