[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Inada Naoki
On Fri, Apr 23, 2021 at 10:33 AM Chris Angelico  wrote:
>
> On Fri, Apr 23, 2021 at 11:22 AM Larry Hastings  wrote:
> >
> >
> > On 4/20/21 10:03 AM, Mark Shannon 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.
> >
> >
> > If I'm reading the library correctly, this is correct--but, perhaps, it 
> > could be remedied by adding a __subclasshook__ to Sequence that looked for 
> > an __iter__ attribute.  That technique might also apply to other ABCs in 
> > collections.abc, Mapping for example.  Would that work, or am I missing an 
> > critical detail?
> >
>
> How would you distinguish between a Sequence and a Mapping? Both have
> __iter__ and __len__. Without actually calling those methods, how
> would the subclass hook tell them apart?
>
> ChrisA

We can add .keys() to Mapping to distinguish Mapping and Sequence.
But it is breaking change, of course. We shouldn't change it.

I think using ABC to distinguish sequence or mapping is a bad idea.

There are three policies:

a) Use duck-typing; just us it as sequence. No type check at all.
b) Use strict type checking; isinstance(x, list) / isinstance(x, (list, tuple)).
c) Use ABC.

But (c) is broken by design. It is not fixable.
IMHO, We should chose (a) or (b) and reject any idea relying on Sequence ABC.

Regards,

-- 
Inada Naoki  
___
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/ESLOPO4GLC2QZW4ZDBYEQDPPGB4ZYDWM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Chris Angelico
On Fri, Apr 23, 2021 at 11:22 AM Larry Hastings  wrote:
>
>
> On 4/20/21 10:03 AM, Mark Shannon 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.
>
>
> If I'm reading the library correctly, this is correct--but, perhaps, it could 
> be remedied by adding a __subclasshook__ to Sequence that looked for an 
> __iter__ attribute.  That technique might also apply to other ABCs in 
> collections.abc, Mapping for example.  Would that work, or am I missing an 
> critical detail?
>

How would you distinguish between a Sequence and a Mapping? Both have
__iter__ and __len__. Without actually calling those methods, how
would the subclass hook tell them apart?

ChrisA
___
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/FJZAJTGCCKJD4MYC3OGRFCGJGBIP5EVT/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Larry Hastings


On 4/20/21 10:03 AM, Mark Shannon 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.



If I'm reading the library correctly, this is correct--but, perhaps, it 
could be remedied by adding a __subclasshook__ to Sequence that looked 
for an __iter__ attribute.  That technique might also apply to other 
ABCs in collections.abc, Mapping for example.  Would that work, or am I 
missing an critical detail?


Cheers,


//arry/

___
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/QRS7JWBP3KX3TYSYDVKILSYOXTLOFUY3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Paul Moore
On Thu, 22 Apr 2021 at 21:40, Adrian Freund  wrote:
> If I understand correctly your concerns with inferring return types for
> inferred protocols are that it might be to restrictive and prevent
> gradual typing. Here are some examples to show how gradual typing would
> still work.

OK, I have no idea what's going on here any more. I have *no* concerns
with inferring the return type. It was you who said that that
inferring would be difficult - the exact quote is "You could
statically type t as Union[Tuple[Literal['version'], int],
Tuple[Literal['name'], str]], but inferring a Protocol for this would
be either very hard or even impossible, especially with even more
complex conditions."

I don't know why you think I have a problem with inferring return
types. All I've ever said is that I thought it might be an interesting
idea if typing an argument as "DuckTyped" could result in type
checkers automatically generated a suitable protocol type, based on
the actual usage of the argument in the function (so that the
programmer doesn't have to explicitly write and maintain a protocol
class in parallel with the code).

> If you have any concrete examples where inferring the return
> type would break gradual typing let me know and I'll have a look at them.

I don't, and I never have. As I say, it seemed to be you who was
claiming that inferring would be too hard.

I don't see much point in continuing this. You seem to be arguing
against points I never made, or maybe I'm completely misunderstanding
you. Either way, we're getting nowhere.

Thanks for taking the time to try to explain, but I think all this has
accomplished is to convince me that there's a "typing mindset" that
embraces a level of strictness that I want nothing to do with. That's
fine, we can agree to differ, but I'm a bit saddened at the thought
that a certain proportion of the information available about typing
might be hard for me to follow because its underlying assumptions are
too different from mine.

Paul
___
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/KADXCO56OFVLILMWWT5GDRGZERBJUQPB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Adrian Freund
On 4/22/21 5:00 PM, Paul Moore wrote:
> On Thu, 22 Apr 2021 at 15:22, Adrian Freund  wrote:
>> On April 22, 2021 3:15:27 PM GMT+02:00, Paul Moore  
>> wrote:
>>> but that's *absolutely* as far as I'd want to go. Note in particular
>>> that I don't want to constrain the return value
>> The problem is that this isn't enough to have a type safe program. You 
need to also constrain the return type to make sure the returned value can be 
safely passed to other functions.
> But I don't want a type safe program. At least not in an absolute
> sense. All I want is for mypy to catch the occasional error I make
> where I pass the wrong parameter. For me, that's the "gradual" in
> "gradual typing" - it's not a lifestyle, just a convenience. You seem
> to be implying that it's "all or nothing".

I don't think that inferring the required return type breaks gradual
typing, but it is required for people who want type safety.

If I understand correctly your concerns with inferring return types for
inferred protocols are that it might be to restrictive and prevent
gradual typing. Here are some examples to show how gradual typing would
still work. If you have any concrete examples where inferring the return
type would break gradual typing let me know and I'll have a look at them.


def foo(x: DuckType):  # x has to have a .bar(self) method.
# The return type of which is inferred as Any, as it isn't used
    x.bar()



def bar(x):
    x.bar()

def foo(x: DuckType):  # x has to have a .read(self) method.
# The return type of which ist inferred as  Any, as the parameter to 
bar
isn't typed.
    bar(x.read())


Contrast that with


def bar(x: DuckType):  # x has to have a .bar(self) method.
# The return type of which is inferred as Any.
    x.bar()

def foo(x: DuckType):  # x has to have a .read(self) method that returns
something with a .bar(self) method.
# If we don't infer the return type our call to bar() might be unsafe
despite both foo and bar being typed.

    bar(x.read())

> I repeat, all I'm proposing is that
>
> def f(x: int): ...
> def g(x: str): ...
>
> def main(t: DuckTyped) -> None:
> if t[0] == 'version':
> f(t[1])
> elif t[0] == 'name':
> g(t[1])
>
> gets interpreted *exactly* the same as if I'd written
>
> class TType(Protocol):
> def __getitem__(self, int): ...
>
> def f(x: int): ...
> def g(x: str): ...
>
> def main(t: TType) -> None:
> if t[0] == 'version':
> f(t[1])
> elif t[0] == 'name':
> g(t[1])
>
> How can you claim that the second example requires that " large parts
> of your codebase will either need explicit annotations or will be
> unchecked"? And if the second example doesn't require that, nor does
> the first because it's equivalent.

Both examples don't check the calls to f and g despite f and g both
being typed functions
and being called from typed functions.

In a real codebase this will lead to a lot more instances of this
happening. It would happen every time you do anything with something
returned from a method on an inferred protocol

>
> Honestly, this conversation is just reinforcing my suspicion that
> people invested in type annotations have a blind spot when it comes to
> dealing with people and use cases that don't need to go "all in" with
> typing :-(

I don't think this is an all in or nothing. You can infer return types
of inferred protocols and still use gradual typing.  It's just that not
inferring return types causes problems for both full and gradual typing.


Adrian Freund



___
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/KVB33BV6T6H7PFXN574CMFZUJOVSVUBV/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Luciano Ramalho
On Thu, Apr 22, 2021 at 5:43 AM Chris Angelico  wrote:
> File-like objects are used VERY frequently in the stdlib, and actual
> open file objects have quite a large interface. The use-case is a
> pretty real one: "if I were to create a simulant file object to pass
> to json.load(), what methods do I need?".

My experience with so-called "file-like objects" is that the interface
required most of the time consists of a single method: read()

> Maybe in some cases, the "smaller protocols" option is practical, but
> it would need to have a useful name.

The authors of the typing module already came up with an excellent
convention. For the narrow protocol I mentioned, the conventional name
would be "SupportsRead". Maybe "SupportsRead[str]" and
"SupportsRead[bytes]".

> For instance, if it needs to be
> readable, iterable, closeable, and autocloseable via
> __enter__/__exit__, that's ... uhh a readable, iterable, closeable
> context manager? Not an improvement over "file-like object".

Yes, file-like objects can and do have lots of methods. Often you
don't need more than read()

Cheers,

Luciano

On Thu, Apr 22, 2021 at 7:04 AM Chris Angelico  wrote:
>
> On Thu, Apr 22, 2021 at 7:53 PM Paul Moore  wrote:
> > I wonder whether type checkers could handle a "magic" type (let's call
> > it DuckTyped for now :-)) which basically means "infer a protocol
> > based on usage in this function". So if I do:
> >
> > def my_fn(f: DuckTyped):
> > with f:
> > data = f.read()
> > for line in f:
> > print(line)
> > f.close()
> >
> > then the type checker would automatically build a protocol type like
> > the one I defined above and use that as the type of f? That would make
> > it much easier to include duck typed arguments in function signatures
> > while keeping the benefits of static type checking.
> >
>
> Someone will likely correct me if this is inaccurate, but my
> understanding is that that's exactly what you get if you just don't
> give a type hint. The point of type hints is to give more information
> to the type checker when it's unable to simply infer from usage and
> context.
>
> ChrisA
> ___
> 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/RW5ACSLJP2RLBZWDGQRGBD6ZAVRUQWMG/
> Code of Conduct: http://python.org/psf/codeofconduct/



-- 
Luciano Ramalho
|  Author of Fluent Python (O'Reilly, 2015)
| http://shop.oreilly.com/product/0636920032519.do
|  Technical Principal at ThoughtWorks
|  Twitter: @ramalhoorg
___
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/HP25YCWUQVGPGWDFFFSNOLQQOHGRKEVG/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Luciano Ramalho
On Thu, Apr 22, 2021 at 6:57 AM Paul Moore  wrote:
>
> On Thu, 22 Apr 2021 at 09:46, Chris Angelico  wrote:
> > Maybe in some cases, the "smaller protocols" option is practical, but
> > it would need to have a useful name. For instance, if it needs to be
> > readable, iterable, closeable, and autocloseable via
> > __enter__/__exit__, that's ... uhh a readable, iterable, closeable
> > context manager? Not an improvement over "file-like object".
>
> Note: I've not used protocols myself, so this is speculation.
>
> Is the name of the protocol important? Specifically, if I do, in my code
>
> class X(Protocol):
> def read(self): ...
> def __iter__(self): ...
> def close(self): ...
> def __enter__(self): ...
> def __exit__(self, exc_type, exc_val, exc_tb): ...
>
> def my_fn(fileobj: X) -> None:
> # my stuff
>

That is not a very good example of a Protocol. If you google for best
practices for interfaces in Go (#golang), you'll find they advocate
for very narrow protocols—what they call "interfaces" we decided to
call "protocols".

Many (perhaps most) protocols in the Go standard library define a single method.

I highly recommend reading up on how "interfaces" are used in Go to
reason about how "protocols" should be used in Python (*)

Cheers,

Luciano

(*) That reminded me of how I found Python. In 1998 I was using Perl,
which had just started to support classes. So in the Perl mailing
lists there were quite a few messages then about how classes were used
in Python. After a few mentions, I read the Python tutorial and never
looked back.

On Thu, Apr 22, 2021 at 6:57 AM Paul Moore  wrote:
>
> On Thu, 22 Apr 2021 at 09:46, Chris Angelico  wrote:
> > Maybe in some cases, the "smaller protocols" option is practical, but
> > it would need to have a useful name. For instance, if it needs to be
> > readable, iterable, closeable, and autocloseable via
> > __enter__/__exit__, that's ... uhh a readable, iterable, closeable
> > context manager? Not an improvement over "file-like object".
>
> Note: I've not used protocols myself, so this is speculation.
>
> Is the name of the protocol important? Specifically, if I do, in my code
>
> class X(Protocol):
> def read(self): ...
> def __iter__(self): ...
> def close(self): ...
> def __enter__(self): ...
> def __exit__(self, exc_type, exc_val, exc_tb): ...
>
> def my_fn(fileobj: X) -> None:
> # my stuff
>
> would that not work? An argument is checked to see if it conforms with
> a protocol by confirming it has the right methods, not by name,
> inheritance or registration. And if you want, you can just call X
> "FileLike", it's only a local name so it won't clash with whatever
> other people (or you, in a different module) want to say is
> "file-like". Of course, that's incredibly verbose and messy, and it
> would result in a huge proliferation of throw-away protocol classes,
> which is probably not a good practice that we'd want to encourage, but
> it works.
>
> IMO, the problem isn't that *technically* static typing excludes the
> more traditional duck typing, but rather that the design, approach and
> as a result the emerging "best practices" are focused around
> inheritance based (is that what people mean by "nominal"?) models, to
> the point where duck typing feels like an afterthought that you have
> to work to include.
>
> I wonder whether type checkers could handle a "magic" type (let's call
> it DuckTyped for now :-)) which basically means "infer a protocol
> based on usage in this function". So if I do:
>
> def my_fn(f: DuckTyped):
> with f:
> data = f.read()
> for line in f:
> print(line)
> f.close()
>
> then the type checker would automatically build a protocol type like
> the one I defined above and use that as the type of f? That would make
> it much easier to include duck typed arguments in function signatures
> while keeping the benefits of static type checking.
>
> I will say that at the moment, this doesn't bother me much personally.
> On the larger projects where I've used typing, we've been fine with
> class-based typing and haven't really needed anything more complex
> like protocols. On smaller projects, I just don't use typing at all.
> Whether this will change if I decide to introduce typing in more
> places, I don't know at the moment. I've also not really used typing
> for public APIs, where an over-restrictive type would be more of an
> issue.
>
> Paul
> ___
> 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/EQDLTZDXEE7RRFCAVCGLR5OTJOWFVXH5/
> Code of Conduct: http://python.org/psf/codeofconduct/



-- 
Luciano Ramalho
|  Author of Fluent Python (O'Reilly, 2015)
| 

[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Luciano Ramalho
On Wed, Apr 21, 2021 at 7:31 PM Paul Bryan  wrote:
> 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.

A HUGE insight I learned studying Go is that Protocols should be
defined near the code that CONSUMES it, and not near the code that
PROVIDES it. That's exactly the opposite of how we use ABCs, or Java
folks use interfaces (most of the time).

Cheers,

Luciano


On Wed, Apr 21, 2021 at 7:31 PM Paul Bryan  wrote:
>
> 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).
>
> 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.
>
> 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  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 

[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Luciano Ramalho
On Wed, Apr 21, 2021 at 4:44 PM Christopher Barker  wrote:
>> 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.

I agree with Christopher here. For duck typing, all we care is that
the method(s) we need are implemented in a sensible way.

> 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).

Also agree, and very often the function cares only about one single method.

> And a lot of the standard library works exactly this way.

Totally. I found it astonishing that PEP 484 did not allow to
correctly annotate LOTS of functions in the standard library,
including built-ins people use every day like `sorted()`. Fortunately,
that was corrected with PEP 544.

> But there is the "culture" of Python -- and it has been very much shifting 
> toward more typing

I disagree because Python is too widespread these days to talk about
"the culture". We'll just need to learn to coexist as groups that use
the language differently.

-- 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?

Maybe you mean this one:

"Python 3 types in the wild: a tale of two type systems"
Metadata:
https://dl.acm.org/doi/10.1145/3426422.3426981
PDF:
http://hirzels.com/martin/papers/dls20-python-types.pdf

> And I've seen a lot more isinstance(Some_ABC) code lately as well.

I believe a lot of that is people coming from statically typed
languages and not feeling comfortable with duck typing, while for some
other reason not adopting type hints.

> 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?).

It is considered best practice in some places. I hope we as a
community never adopt it as the canonical way.

> Maybe it is -- but if the community is moving that way, we should be honest 
> about it.

Clearly parts of the community are moving that way. The paper I linked
shows the use of type hints is still very limited in their sample.

>> 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.

It is not just nominal typing because of the subclass hook.

> 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).

Yes. I wish Alex joined this conversation.

Cheers,

Luciano

On Wed, Apr 21, 2021 at 8:28 PM Luciano Ramalho  wrote:
>
> On Wed, Apr 21, 2021 at 4:44 PM Christopher Barker  
> wrote:
> >> 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.
>
> I agree with Christopher here. For duck typing, all we care is that
> the method(s) we need are implemented in a sensible way.
>
> > 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).
>
> Also agree, and very often the function cares only about one single method.
>
> > And a lot of the standard library works exactly this way.
>
> Totally. I found it astonishing that PEP 484 did not allow to
> correctly annotate LOTS of functions in the standard library,
> including built-ins people use every day like `sorted()`. Fortunately,
> that was corrected with PEP 544.
>
> > But there is the "culture" of Python -- and it has been very much shifting 
> > toward more typing
>
> I disagree because Python is too widespread these days to talk about
> 

[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Terry Reedy

On 4/22/2021 9:15 AM, Paul Moore wrote:


Absolutely, I see no problem with "use duck typing for this argument"
being opt-in.


As in x: 'duck'? or x: '!', where '!' means
 'infer it!', or

from typing import Infer
... x: Infer
?

Ditto for ->  ?

--
Terry Jan Reedy

___
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/NSALGTJQIITQO3ZHI7E5G2J77JQERAKZ/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Christopher Barker
On Thu, Apr 22, 2021 at 10:47 AM Matthew Einhorn  wrote:
> In PyCharm, the above code will result in it highlighting the number `12`
with the following warning: "Type 'int' doesn't have expected attribute
'close'"

Which gives yet another use for type hints: helping out IDEs.


> If instead you add an `elif isinstance(t, str):`, under that condition
it'll auto-complete `t.` with all string properties/methods.

now this makes me nervous -- if folks start adding isinstance checks to
make their IDE more helpful , we are rally getting away from Duck Typing.

However, you could have presumably typed it as Sequence[int] and gotten all
the benefits of duck typing and IDE completion.

However, if code were to really use a duck-typed "str-like" i would produce
a failure in the type checker even if it was perfectly functional.

NOTE: str is not a great example, as it's one type that we often do need to
explicitly check -- to make the distinction between a Sequence of strings,
which a str is, and a str itself.  And str is so fundamental and complex a
type it's rarely duck-typed anyway.

-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/EGBSQALPGCTLAPM6FLIQLDV2YD2OLVAB/
> Code of Conduct: http://python.org/psf/codeofconduct/
>


-- 
Christopher Barker, PhD (Chris)

Python Language Consulting
  - Teaching
  - Scientific Software Development
  - Desktop GUI and Web Development
  - wxPython, numpy, scipy, Cython
___
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/PTVPRVZDZLXGLOM5WREHWQX3ZWUKO5TS/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Matthew Einhorn
On Thu, Apr 22, 2021, at 1:01 PM, Brett Cannon wrote:
> 
> 
> On Thu, Apr 22, 2021 at 4:11 AM Paul Moore  wrote:
>> On Thu, 22 Apr 2021 at 11:21, Paul Moore  wrote:
>> >
>> > On Thu, 22 Apr 2021 at 11:06, Chris Angelico  wrote:
>> > >
>> > > Someone will likely correct me if this is inaccurate, but my
>> > > understanding is that that's exactly what you get if you just don't
>> > > give a type hint. The point of type hints is to give more information
>> > > to the type checker when it's unable to simply infer from usage and
>> > > context.
>> >
>> > Hmm, I sort of wondered about that as I wrote it. But in which case,
>> > what's the problem here? My understanding was that people were
>> > concerned that static typing was somehow in conflict with duck typing,
>> > but if the static checkers enforce the inferred duck type on untyped
>> > arguments, then that doesn't seem to be the case. Having said that, I
>> > thought that untyped arguments were treated as if they had a type of
>> > "Any", which means "don't type check".
>> 
>> Looks like it doesn't:
>> 
>> > cat .\test.py
>> def example(f) -> None:
>> f.close()
>> 
>> import sys
>> example(12)
>> example(sys.stdin)
>> PS 12:00 00:00.009 C:\Work\Scratch\typing
>> > mypy .\test.py
>> Success: no issues found in 1 source file
>> 
>> What I was after was something that gave an error on the first call,
>> but not on the second. Compare this:
>>  

In PyCharm, the above code will result in it highlighting the number `12` with 
the following warning: "Type 'int' doesn't have expected attribute 'close'"

Similarly, for:

def f(x: int): ...
def g(x: str): ...

def main(t: DuckTyped) -> None:
if t[0] == 'version':
f(t[1])
elif t[0] == 'name':
g(t[1])


If you replace `f(t[1])` or `g(t[1])` with just `t.` and activate 
auto-completion, it'll show `__getitem__` as an option (but it won't show any 
additional int/str methods).

If instead you add an `elif isinstance(t, str):`, under that condition it'll 
auto-complete `t.` with all string properties/methods.___
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/EGBSQALPGCTLAPM6FLIQLDV2YD2OLVAB/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Brett Cannon
On Thu, Apr 22, 2021 at 4:11 AM Paul Moore  wrote:

> On Thu, 22 Apr 2021 at 11:21, Paul Moore  wrote:
> >
> > On Thu, 22 Apr 2021 at 11:06, Chris Angelico  wrote:
> > >
> > > Someone will likely correct me if this is inaccurate, but my
> > > understanding is that that's exactly what you get if you just don't
> > > give a type hint. The point of type hints is to give more information
> > > to the type checker when it's unable to simply infer from usage and
> > > context.
> >
> > Hmm, I sort of wondered about that as I wrote it. But in which case,
> > what's the problem here? My understanding was that people were
> > concerned that static typing was somehow in conflict with duck typing,
> > but if the static checkers enforce the inferred duck type on untyped
> > arguments, then that doesn't seem to be the case. Having said that, I
> > thought that untyped arguments were treated as if they had a type of
> > "Any", which means "don't type check".
>
> Looks like it doesn't:
>
> > cat .\test.py
> def example(f) -> None:
> f.close()
>
> import sys
> example(12)
> example(sys.stdin)
> PS 12:00 00:00.009 C:\Work\Scratch\typing
> > mypy .\test.py
> Success: no issues found in 1 source file
>
> What I was after was something that gave an error on the first call,
> but not on the second. Compare this:
>
> > cat .\test.py
> from typing import Protocol
>
> class X(Protocol):
> def close(self): ...
>
> def example(f: X) -> None:
> f.close()
>
> import sys
> example(12)
> example(sys.stdin)
> PS 12:03 00:00.015 C:\Work\Scratch\typing
> > mypy .\test.py
> test.py:10: error: Argument 1 to "example" has incompatible type
> "int"; expected "X"
> Found 1 error in 1 file (checked 1 source file)
>

Do note that this is only based on what mypy does, not necessarily what all
Python type checkers do. I.e. it's quite possible pytype, pyre, or pyright
infer more (especially https://pypi.org/project/pytype/ since they
specifically say they infer types).
___
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/Y42GJAJH3BSW5ZDLZQKDZDWNAGRMXDQ3/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Adrian Freund



On April 22, 2021 3:15:27 PM GMT+02:00, Paul Moore  wrote:
>On Thu, 22 Apr 2021 at 13:23, Adrian Freund  wrote:
>>
>> According to PEP 484 all missing annotations in checked functions should be 
>> handled as Any. Any is compatible with all types.
>
>Yep, that's what I understood to be the case.
>
>> I think from a technical standpoint it should be possible to infer protocols 
>> for arguments for most functions, but there are some edge cases where this 
>> would not be possible, making it impractical to make this the default 
>> behavior. Having an annotation to make a type checker infer a protocol would 
>> be interesting though.
>
>Absolutely, I see no problem with "use duck typing for this argument"
>being opt-in.
>
>> For example:
>>
>> def f(x: int): ...
>> def g(x: str): ...
>>
>> def main(t):
>> if t[0] == 'version':
>> f(t[1])
>> elif t[0] == 'name':
>> g(t[1])
>>
>>
>> You could statically type t as Union[Tuple[Literal['version'], int], 
>> Tuple[Literal['name'], str]], but inferring a Protocol for this would be 
>> either very hard or even impossible, especially with even more complex 
>> conditions.
>
>Yes, but that's inferred static typing which is *not* what I was
>proposing.
I think I understood what you were proposing, but my example might have been 
less than ideal. Sorry for that.
 I mixed some static types in there to simplify it. The union wasn't meant at 
what it should infer but was meant as a comparison to what we would to 
currently, with static, nominal typing.

Let me try again without static types.

def file(x):
print(x.read())  # x has to have .read(): object

def string(x):
print(str(x))  # x has to have .__str__(self): object

def main(t):
if t[0] == 'file':
file(t[1])
elif t[0] == 'string':
string(t[1])

Here we can infer that t has to have a __getitem__(self, idx: int), but we 
can't infer it's return type

>I was suggesting that the checker could easily infer that t
>must have a __getitem__ method, and nothing more. So the protocol to
>infer is
>
>class TypeOfT(Protocol):
>def __getitem__(self, idx): ...
>
>It would be nice to go one step further and infer
>
>class TypeOfT(Protocol):
>def __getitem__(self, idx: int): ...
>
>but that's *absolutely* as far as I'd want to go. Note in particular
>that I don't want to constrain the return value 
The problem is that this isn't enough to have a type safe program. You need to 
also constrain the return type to make sure the returned value can be safely 
passed to other functions.
If you don't do this large parts of your codebase will either need explicit 
annotations or will be unchecked.
>- we've no way to know
>what type it might have in the general case. IMO, inferring anything
>else would over-constrain t - there's nothing in the available
>information, for example, that says t must be a tuple, or a list, or
>that t[3] should have any particular type, or anything like that.
You can infer the return type of a function by looking at all the returns it 
contains, and inferring the types of the returned expressions. That isn't too 
hard and pytype for example already does it.

You can infer the return type a protocol function should have by looking at all 
the places it's result are used.
If you have inferred return types then constraining return types using inferred 
protocols would be practical in my opinion.
>
>My instinct is that working out that t needs to have a __getitem__
>that takes an int is pretty straightforward, as all you have to do is
>look at where t is used in the function. Four places, all followed by
>[] with a literal integer in the brackets. That's it. I fully
>appreciate that writing *code* to do that can be a lot harder than it
>looks, but that's an implementation question, not a matter of whether
>it's reasonable as a proposal in theory.
>
>This feels like *precisely* where there seems to be a failure of
>communication between the static typing and the duck typing worlds. I
>have no idea what I said that would make you think that I wanted
>anything like that Union type you quoted above. And yet obviously, you
>somehow got that message from what I did say.
Like I said above the Union. Was just meant as an example of that we would do 
with static, nominal typing, not what we want with duck typing. Sorry for the 
misunderstanding.
>
>Anyway, as I said this is just an interesting idea as far as I'm
>concerned. I've no actual need for it right now, so I'm happy to leave
>it to the mypy developers whether they want to do anything with it.
>
>Paul
___
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/AG6LWGMUNGP5O3PXJZUVDRRXO5VTJ7FW/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Adrian Freund
According to PEP 484 all missing annotations in checked functions should be 
handled as Any. Any is compatible with all types.

I think from a technical standpoint it should be possible to infer protocols 
for arguments for most functions, but there are some edge cases where this 
would not be possible, making it impractical to make this the default behavior. 
Having an annotation to make a type checker infer a protocol would be 
interesting though.

For example:

def f(x: int): ...
def g(x: str): ...

def main(t):
if t[0] == 'version':
f(t[1])
elif t[0] == 'name':
g(t[1])


You could statically type t as Union[Tuple[Literal['version'], int], 
Tuple[Literal['name'], str]], but inferring a Protocol for this would be either 
very hard or even impossible, especially with even more complex conditions.


Adrian Freund

On April 22, 2021 1:04:11 PM GMT+02:00, Paul Moore  wrote:
>On Thu, 22 Apr 2021 at 11:21, Paul Moore  wrote:
>>
>> On Thu, 22 Apr 2021 at 11:06, Chris Angelico  wrote:
>> >
>> > Someone will likely correct me if this is inaccurate, but my
>> > understanding is that that's exactly what you get if you just don't
>> > give a type hint. The point of type hints is to give more information
>> > to the type checker when it's unable to simply infer from usage and
>> > context.
>>
>> Hmm, I sort of wondered about that as I wrote it. But in which case,
>> what's the problem here? My understanding was that people were
>> concerned that static typing was somehow in conflict with duck typing,
>> but if the static checkers enforce the inferred duck type on untyped
>> arguments, then that doesn't seem to be the case. Having said that, I
>> thought that untyped arguments were treated as if they had a type of
>> "Any", which means "don't type check".
>
>Looks like it doesn't:
>
>> cat .\test.py
>def example(f) -> None:
>f.close()
>
>import sys
>example(12)
>example(sys.stdin)
>PS 12:00 00:00.009 C:\Work\Scratch\typing
>> mypy .\test.py
>Success: no issues found in 1 source file
>
>What I was after was something that gave an error on the first call,
>but not on the second. Compare this:
>
>> cat .\test.py
>from typing import Protocol
>
>class X(Protocol):
>def close(self): ...
>
>def example(f: X) -> None:
>f.close()
>
>import sys
>example(12)
>example(sys.stdin)
>PS 12:03 00:00.015 C:\Work\Scratch\typing
>> mypy .\test.py
>test.py:10: error: Argument 1 to "example" has incompatible type
>"int"; expected "X"
>Found 1 error in 1 file (checked 1 source file)
>
>Paul
>___
>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/54C6G2JLYYD6B37J5KVKPCKSQDCGLRKA/
>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/M4XDZUPWKPGRO3NF5VONG22YHOHAYZCM/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Sebastian Rittau

Am 22.04.21 um 10:42 schrieb Chris Angelico:

File-like objects are used VERY frequently in the stdlib, and actual
open file objects have quite a large interface. The use-case is a
pretty real one: "if I were to create a simulant file object to pass
to json.load(), what methods do I need?".

Maybe in some cases, the "smaller protocols" option is practical, but
it would need to have a useful name. For instance, if it needs to be
readable, iterable, closeable, and autocloseable via
__enter__/__exit__, that's ... uhh a readable, iterable, closeable
context manager? Not an improvement over "file-like object".


Experience from typeshed shows that many functions in the stdlib and 
third-party libraries only use one or very few methods, very often just 
read() or write(). From a practical standpoint, small protocols seem 
quite feasible. These are quite an improvement over "file-like" objects, 
where no one knows what that actually means.


 - Sebastian


___
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/H33OH6GGIGHR7SVE6NL32I7OBO7B7F7E/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Luciano Ramalho
Please let's not try to make Python a "typesafe" language. The success
of Python owes a lot to the fact that duck typing is approachable,
flexible and powerful.

Even if you advocate static typing, I think it's a very good idea to
limit the ambition of the type system if you want to keep most users
happy—despite the opinion of language lawyers.

Go is by far the most successful statically typed language created so
far in the 21st century, and I believe a lot of that success is due to
the simplicity of its type system. It's way more successful than Rust,
possibly for this very reason.

I find it admirable that Go was released without generics, which were
seriously considered only after its runaway success. Generics will
appear in Go 1.17, scheduled for August, 2021—9 years after Go 1.0.

Please let us heed the wise words of Brian W. Kernighan and Alan A. A.
Donovan in the introduction of "The Go Programming Language" book, a
masterpiece (even if you don't like the language, the book is one of
the best introduction to any language that I've ever read):

"""
Go has enough of a type system to avoid most of the careless mistakes
that plague programmers in dynamic languages, but it has a simpler
type system than comparable typed languages. This approach can
sometimes lead to isolated pockets of ‘‘untyped’’ programming within a
broader framework of types, and Go programmers do not go to the
lengths that C++ or Haskell programmers do to express safety
properties as type-based proofs. But in practice Go gives programmers
much of the safety and run-time performance benefits of a relatively
strong type system without the burden of a complex one.
"""

I also consider the support of static duck typing and goose typing
(via runtime type assertions and type switches) key factors that make
Go an excellent language to "get stuff done"—the best compliment Dave
Beazley traditionally has for Python.

Cheers,

Luciano

On Thu, Apr 22, 2021 at 12:05 PM Paul Moore  wrote:
>
> On Thu, 22 Apr 2021 at 15:22, Adrian Freund  wrote:
> >
> > On April 22, 2021 3:15:27 PM GMT+02:00, Paul Moore  
> > wrote:
>
> > >but that's *absolutely* as far as I'd want to go. Note in particular
> > >that I don't want to constrain the return value
> > The problem is that this isn't enough to have a type safe program. You need 
> > to also constrain the return type to make sure the returned value can be 
> > safely passed to other functions.
>
> But I don't want a type safe program. At least not in an absolute
> sense. All I want is for mypy to catch the occasional error I make
> where I pass the wrong parameter. For me, that's the "gradual" in
> "gradual typing" - it's not a lifestyle, just a convenience. You seem
> to be implying that it's "all or nothing".
>
> > If you don't do this large parts of your codebase will either need explicit 
> > annotations or will be unchecked.
>
> That's just not true. (And even if it were true, you're assuming that
> I care - I've already said that my goal is much more relaxed than
> complete type safety).
>
> I repeat, all I'm proposing is that
>
> def f(x: int): ...
> def g(x: str): ...
>
> def main(t: DuckTyped) -> None:
> if t[0] == 'version':
> f(t[1])
> elif t[0] == 'name':
> g(t[1])
>
> gets interpreted *exactly* the same as if I'd written
>
> class TType(Protocol):
> def __getitem__(self, int): ...
>
> def f(x: int): ...
> def g(x: str): ...
>
> def main(t: TType) -> None:
> if t[0] == 'version':
> f(t[1])
> elif t[0] == 'name':
> g(t[1])
>
> How can you claim that the second example requires that " large parts
> of your codebase will either need explicit annotations or will be
> unchecked"? And if the second example doesn't require that, nor does
> the first because it's equivalent.
>
> Honestly, this conversation is just reinforcing my suspicion that
> people invested in type annotations have a blind spot when it comes to
> dealing with people and use cases that don't need to go "all in" with
> typing :-(
>
> Paul
> ___
> 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/CUZNKEA357N3672CCRA7DZ6C4WABN6FK/
> Code of Conduct: http://python.org/psf/codeofconduct/



-- 
Luciano Ramalho
|  Author of Fluent Python (O'Reilly, 2015)
| http://shop.oreilly.com/product/0636920032519.do
|  Technical Principal at ThoughtWorks
|  Twitter: @ramalhoorg
___
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/STAULSS6WI7DLSHEXYXHFLHQFVWAIAKY/
Code of Conduct: 

[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Paul Moore
On Thu, 22 Apr 2021 at 15:22, Adrian Freund  wrote:
>
> On April 22, 2021 3:15:27 PM GMT+02:00, Paul Moore  
> wrote:

> >but that's *absolutely* as far as I'd want to go. Note in particular
> >that I don't want to constrain the return value
> The problem is that this isn't enough to have a type safe program. You need 
> to also constrain the return type to make sure the returned value can be 
> safely passed to other functions.

But I don't want a type safe program. At least not in an absolute
sense. All I want is for mypy to catch the occasional error I make
where I pass the wrong parameter. For me, that's the "gradual" in
"gradual typing" - it's not a lifestyle, just a convenience. You seem
to be implying that it's "all or nothing".

> If you don't do this large parts of your codebase will either need explicit 
> annotations or will be unchecked.

That's just not true. (And even if it were true, you're assuming that
I care - I've already said that my goal is much more relaxed than
complete type safety).

I repeat, all I'm proposing is that

def f(x: int): ...
def g(x: str): ...

def main(t: DuckTyped) -> None:
if t[0] == 'version':
f(t[1])
elif t[0] == 'name':
g(t[1])

gets interpreted *exactly* the same as if I'd written

class TType(Protocol):
def __getitem__(self, int): ...

def f(x: int): ...
def g(x: str): ...

def main(t: TType) -> None:
if t[0] == 'version':
f(t[1])
elif t[0] == 'name':
g(t[1])

How can you claim that the second example requires that " large parts
of your codebase will either need explicit annotations or will be
unchecked"? And if the second example doesn't require that, nor does
the first because it's equivalent.

Honestly, this conversation is just reinforcing my suspicion that
people invested in type annotations have a blind spot when it comes to
dealing with people and use cases that don't need to go "all in" with
typing :-(

Paul
___
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/CUZNKEA357N3672CCRA7DZ6C4WABN6FK/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Paul Moore
On Thu, 22 Apr 2021 at 13:23, Adrian Freund  wrote:
>
> According to PEP 484 all missing annotations in checked functions should be 
> handled as Any. Any is compatible with all types.

Yep, that's what I understood to be the case.

> I think from a technical standpoint it should be possible to infer protocols 
> for arguments for most functions, but there are some edge cases where this 
> would not be possible, making it impractical to make this the default 
> behavior. Having an annotation to make a type checker infer a protocol would 
> be interesting though.

Absolutely, I see no problem with "use duck typing for this argument"
being opt-in.

> For example:
>
> def f(x: int): ...
> def g(x: str): ...
>
> def main(t):
> if t[0] == 'version':
> f(t[1])
> elif t[0] == 'name':
> g(t[1])
>
>
> You could statically type t as Union[Tuple[Literal['version'], int], 
> Tuple[Literal['name'], str]], but inferring a Protocol for this would be 
> either very hard or even impossible, especially with even more complex 
> conditions.

Yes, but that's inferred static typing which is *not* what I was
proposing. I was suggesting that the checker could easily infer that t
must have a __getitem__ method, and nothing more. So the protocol to
infer is

class TypeOfT(Protocol):
def __getitem__(self, idx): ...

It would be nice to go one step further and infer

class TypeOfT(Protocol):
def __getitem__(self, idx: int): ...

but that's *absolutely* as far as I'd want to go. Note in particular
that I don't want to constrain the return value - we've no way to know
what type it might have in the general case. IMO, inferring anything
else would over-constrain t - there's nothing in the available
information, for example, that says t must be a tuple, or a list, or
that t[3] should have any particular type, or anything like that.

My instinct is that working out that t needs to have a __getitem__
that takes an int is pretty straightforward, as all you have to do is
look at where t is used in the function. Four places, all followed by
[] with a literal integer in the brackets. That's it. I fully
appreciate that writing *code* to do that can be a lot harder than it
looks, but that's an implementation question, not a matter of whether
it's reasonable as a proposal in theory.

This feels like *precisely* where there seems to be a failure of
communication between the static typing and the duck typing worlds. I
have no idea what I said that would make you think that I wanted
anything like that Union type you quoted above. And yet obviously, you
somehow got that message from what I did say.

Anyway, as I said this is just an interesting idea as far as I'm
concerned. I've no actual need for it right now, so I'm happy to leave
it to the mypy developers whether they want to do anything with it.

Paul
___
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/CU7OES4P3KUCQMD3U5766XVOESL43DRF/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Paul Moore
On Thu, 22 Apr 2021 at 11:21, Paul Moore  wrote:
>
> On Thu, 22 Apr 2021 at 11:06, Chris Angelico  wrote:
> >
> > Someone will likely correct me if this is inaccurate, but my
> > understanding is that that's exactly what you get if you just don't
> > give a type hint. The point of type hints is to give more information
> > to the type checker when it's unable to simply infer from usage and
> > context.
>
> Hmm, I sort of wondered about that as I wrote it. But in which case,
> what's the problem here? My understanding was that people were
> concerned that static typing was somehow in conflict with duck typing,
> but if the static checkers enforce the inferred duck type on untyped
> arguments, then that doesn't seem to be the case. Having said that, I
> thought that untyped arguments were treated as if they had a type of
> "Any", which means "don't type check".

Looks like it doesn't:

> cat .\test.py
def example(f) -> None:
f.close()

import sys
example(12)
example(sys.stdin)
PS 12:00 00:00.009 C:\Work\Scratch\typing
> mypy .\test.py
Success: no issues found in 1 source file

What I was after was something that gave an error on the first call,
but not on the second. Compare this:

> cat .\test.py
from typing import Protocol

class X(Protocol):
def close(self): ...

def example(f: X) -> None:
f.close()

import sys
example(12)
example(sys.stdin)
PS 12:03 00:00.015 C:\Work\Scratch\typing
> mypy .\test.py
test.py:10: error: Argument 1 to "example" has incompatible type
"int"; expected "X"
Found 1 error in 1 file (checked 1 source file)

Paul
___
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/54C6G2JLYYD6B37J5KVKPCKSQDCGLRKA/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Paul Moore
On Thu, 22 Apr 2021 at 11:06, Chris Angelico  wrote:
>
> On Thu, Apr 22, 2021 at 7:53 PM Paul Moore  wrote:
> > I wonder whether type checkers could handle a "magic" type (let's call
> > it DuckTyped for now :-)) which basically means "infer a protocol
> > based on usage in this function". So if I do:
> >
> > def my_fn(f: DuckTyped):
> > with f:
> > data = f.read()
> > for line in f:
> > print(line)
> > f.close()
> >
> > then the type checker would automatically build a protocol type like
> > the one I defined above and use that as the type of f? That would make
> > it much easier to include duck typed arguments in function signatures
> > while keeping the benefits of static type checking.
> >
>
> Someone will likely correct me if this is inaccurate, but my
> understanding is that that's exactly what you get if you just don't
> give a type hint. The point of type hints is to give more information
> to the type checker when it's unable to simply infer from usage and
> context.

Hmm, I sort of wondered about that as I wrote it. But in which case,
what's the problem here? My understanding was that people were
concerned that static typing was somehow in conflict with duck typing,
but if the static checkers enforce the inferred duck type on untyped
arguments, then that doesn't seem to be the case. Having said that, I
thought that untyped arguments were treated as if they had a type of
"Any", which means "don't type check".

So I guess the point here is that either the typing
community/documentation isn't doing a very good job of explaining how
duck types and static types work together, or that people who like
duck typed interfaces¹ aren't reading the available documentation in
type checkers explaining how to do that with static typing :-)

Paul

¹ And I include myself in that - maybe I need to go and read the mypy
docs properly rather than just learning what I need by following
examples in existing code...
___
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/IRSXXYHMYCRBBA5HKPNZ7OJDRTEGUAG7/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Chris Angelico
On Thu, Apr 22, 2021 at 7:53 PM Paul Moore  wrote:
> I wonder whether type checkers could handle a "magic" type (let's call
> it DuckTyped for now :-)) which basically means "infer a protocol
> based on usage in this function". So if I do:
>
> def my_fn(f: DuckTyped):
> with f:
> data = f.read()
> for line in f:
> print(line)
> f.close()
>
> then the type checker would automatically build a protocol type like
> the one I defined above and use that as the type of f? That would make
> it much easier to include duck typed arguments in function signatures
> while keeping the benefits of static type checking.
>

Someone will likely correct me if this is inaccurate, but my
understanding is that that's exactly what you get if you just don't
give a type hint. The point of type hints is to give more information
to the type checker when it's unable to simply infer from usage and
context.

ChrisA
___
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/RW5ACSLJP2RLBZWDGQRGBD6ZAVRUQWMG/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Paul Moore
On Thu, 22 Apr 2021 at 09:46, Chris Angelico  wrote:
> Maybe in some cases, the "smaller protocols" option is practical, but
> it would need to have a useful name. For instance, if it needs to be
> readable, iterable, closeable, and autocloseable via
> __enter__/__exit__, that's ... uhh a readable, iterable, closeable
> context manager? Not an improvement over "file-like object".

Note: I've not used protocols myself, so this is speculation.

Is the name of the protocol important? Specifically, if I do, in my code

class X(Protocol):
def read(self): ...
def __iter__(self): ...
def close(self): ...
def __enter__(self): ...
def __exit__(self, exc_type, exc_val, exc_tb): ...

def my_fn(fileobj: X) -> None:
# my stuff

would that not work? An argument is checked to see if it conforms with
a protocol by confirming it has the right methods, not by name,
inheritance or registration. And if you want, you can just call X
"FileLike", it's only a local name so it won't clash with whatever
other people (or you, in a different module) want to say is
"file-like". Of course, that's incredibly verbose and messy, and it
would result in a huge proliferation of throw-away protocol classes,
which is probably not a good practice that we'd want to encourage, but
it works.

IMO, the problem isn't that *technically* static typing excludes the
more traditional duck typing, but rather that the design, approach and
as a result the emerging "best practices" are focused around
inheritance based (is that what people mean by "nominal"?) models, to
the point where duck typing feels like an afterthought that you have
to work to include.

I wonder whether type checkers could handle a "magic" type (let's call
it DuckTyped for now :-)) which basically means "infer a protocol
based on usage in this function". So if I do:

def my_fn(f: DuckTyped):
with f:
data = f.read()
for line in f:
print(line)
f.close()

then the type checker would automatically build a protocol type like
the one I defined above and use that as the type of f? That would make
it much easier to include duck typed arguments in function signatures
while keeping the benefits of static type checking.

I will say that at the moment, this doesn't bother me much personally.
On the larger projects where I've used typing, we've been fine with
class-based typing and haven't really needed anything more complex
like protocols. On smaller projects, I just don't use typing at all.
Whether this will change if I decide to introduce typing in more
places, I don't know at the moment. I've also not really used typing
for public APIs, where an over-restrictive type would be more of an
issue.

Paul
___
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/EQDLTZDXEE7RRFCAVCGLR5OTJOWFVXH5/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Chris Angelico
On Thu, Apr 22, 2021 at 5:03 PM Ryan Gonzalez  wrote:
>
> On Apr 21, 2021, 5:29 PM -0500, Paul Bryan , wrote:
>
> 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).
>
>
> I'd argue that, if you frequently have cases where functions use a relatively 
> small subset of a much larger interface, it's simply that your interfaces are 
> too large. You're always free to define your own, smaller protocols that just 
> implement the subset of the interfaces you need.
>

File-like objects are used VERY frequently in the stdlib, and actual
open file objects have quite a large interface. The use-case is a
pretty real one: "if I were to create a simulant file object to pass
to json.load(), what methods do I need?".

Maybe in some cases, the "smaller protocols" option is practical, but
it would need to have a useful name. For instance, if it needs to be
readable, iterable, closeable, and autocloseable via
__enter__/__exit__, that's ... uhh a readable, iterable, closeable
context manager? Not an improvement over "file-like object".

ChrisA
___
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/2LQQXLETT6TFB4UATJBEN5HDI47KAZME/
Code of Conduct: http://python.org/psf/codeofconduct/


[Python-Dev] Re: Keeping Python a Duck Typed Language.

2021-04-22 Thread Ryan Gonzalez
On Apr 21, 2021, 5:29 PM -0500, Paul Bryan , wrote:
> 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).

I'd argue that, if you frequently have cases where functions use a relatively 
small subset of a much larger interface, it's simply that your interfaces are 
too large. You're always free to define your own, smaller protocols that just 
implement the subset of the interfaces you need.
>
> 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 mentioned above that defining smaller protocols is an option. If the main 
concern is due to wanting to define them in the type signature, or wanting to 
ensure the types match the base interface, then that's not new: TypeScript does 
them both (well, at least you could accomplish the latter roughly using 
intersection types).
>
> 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  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,