Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   Python (http://www.velocityreviews.com/forums/f43-python.html)
-   -   duck typing assert■ (http://www.velocityreviews.com/forums/t954345-duck-typing-assertth.html)

Andriy Kornatskyy 11-08-2012 05:34 PM

duck typing assert■
 

People who come from strongly typed languages that offer interfaces often are confused by lack of one in Python. Python, being dynamic typing programming language, follows duck typing principal. It can as simple as this:
*
assert looks(Foo).like(IFoo)
*
The post below shows how programmer can assert duck typing between two Python classes:
*
http://mindref.blogspot.com/2012/11/...ng-assert.html
*
Comments or suggestions are welcome.
*
Thanks.
*
Andriy Kornatskyy

Steven D'Aprano 11-08-2012 11:33 PM

Re: duck typing assertÔÇĆ
 
On Thu, 08 Nov 2012 20:34:58 +0300, Andriy Kornatskyy wrote:

> People who come from strongly typed languages that offer interfaces
> often are confused by lack of one in Python. Python, being dynamic
> typing programming language, follows duck typing principal. It can as
> simple as this:
> ┬*
> assert looks(Foo).like(IFoo)


How very cute. And I don't mean that in a good way.

Why is this a class with a method, instead of a function that takes two
class arguments (plus any optional arguments needed)?

looks_like(Foo, IFoo)

is less "cute", reads better to English speakers, and much more Pythonic.
This isn't Java, not everything needs to be a class.


> The post below shows how programmer can assert duck typing between two
> Python classes:
> ┬*
> http://mindref.blogspot.com/2012/11/...ng-assert.html


I don't understand the emphasis on assert for this code. It is enough
that looks() return a flag. The caller can then use that as an assertion:

assert looks(Spam).like(Ham)

or as a conditional:

if looks(food).like(Meat):
...
else:
...


Assertions are only one use for this check, and in my opinion, the least
useful one.

And why the warnings? In my opinion, using the warning mechanism as a way
to communicate the differences between the classes is an abuse of
warnings: they're not *warnings*, they are *diagnostic information*.

It is also fragile: the caller may have filtered warnings, and will not
see the messages you generate.

Lastly, I do not understand the purpose of this "wheezy.core" package.
Does it have something to do with Ubuntu Wheezy? The documentation is
unclear -- it refers to it as a "Python package" that "provides core
features", but doesn't say what the purpose of the package is: core
features of *what*? And the examples.rst file doesn't show any examples.

https://bitbucket.org/akorn/wheezy.c...c/examples.rst


--
Steven

Ian Kelly 11-09-2012 01:00 AM

Re: duck typing assert
 
On Thu, Nov 8, 2012 at 4:33 PM, Steven D'Aprano
<steve+comp.lang.python@pearwood.info> wrote:
> On Thu, 08 Nov 2012 20:34:58 +0300, Andriy Kornatskyy wrote:
>
>> People who come from strongly typed languages that offer interfaces
>> often are confused by lack of one in Python. Python, being dynamic
>> typing programming language, follows duck typing principal. It can as
>> simple as this:
>>
>> assert looks(Foo).like(IFoo)

>
> How very cute. And I don't mean that in a good way.
>
> Why is this a class with a method, instead of a function that takes two
> class arguments (plus any optional arguments needed)?
>
> looks_like(Foo, IFoo)
>
> is less "cute", reads better to English speakers, and much more Pythonic.
> This isn't Java, not everything needs to be a class.


I disagree. Does that test whether Foo looks like IFoo, or IFoo looks
like Foo? Of course, given the naming convention and the example,
it's easy to work out, but when you're trying to *write* that from
memory, it could be a nuisance to remember the proper order. This is
already a wart of isinstance and issubclass.

looks(Foo).like(IFoo), on the other hand, is crystal clear about which
argument is which.

Chris Angelico 11-09-2012 06:14 AM

Re: duck typing assert
 
On Fri, Nov 9, 2012 at 12:00 PM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> looks(Foo).like(IFoo), on the other hand, is crystal clear about which
> argument is which.


I'm not so sure that it is, tbh. If you read it like an English
sentence, it's clearly testing whether Foo matches the template in
IFoo, but which are you more likely to do: test one class to see if it
satisfies lots of templates, or test one template against every class
you meet? I think probably the latter is, if not more likely than the
former, at least sufficiently plausible as to create confusion. It
makes very good sense to say:

duckmatch(IFoo).compare(Foo)

ie with the arguments the other way.

ChrisA

Andriy Kornatskyy 11-09-2012 10:26 AM

RE: duck typing assert
 

Thank you for all comments.

> It*makes very good sense to say:
>
> duckmatch(IFoo).compare(Foo)


Since we do duck match of IFoo... but there is no `duck match`, there is `duck test`.*I believe instead of `compare` is more readable with `equals`. Than it is more from*mathematics - precise answer...*that you can not guarantee at all in dynamic programming language. So it false to use suchwording to reflect this check. We can only make an assumption that one looks like the other (similar)... with some limitation of cause... understanding what is `duck test`.

http://en.wikipedia.org/wiki/Duck_test

The intent is to make such language `construct` so it reads as English sentence that make sense, and not mandatory `pythonic` way (readability counts, java smokes aside).

is_similar(Foo).to(IFoo) # <= but we lost `duck test` sense here?

Words `looks` and `like` are coming from duck test and point also direction:

# 1
looks(Foo).like(IFoo, notice=['__len__'], ignore_funcs=['foo'], ignore_argspec['bar'])

English sentence equivalent: if functions in Foo looks like one in IFoo than, probably, IFoo can be replaced with Foo; notice to check __len__, it is safe to ignore function `foo` and arguments passed to `bar`.

# 2
looks(Foo, notice=['__len__'], ignore_funcs=['foo'], ignore_argspec['bar']).like(IFoo)

English sentence equivalent:*while looking at Foo notice to check `__len__`, it is safe to ignore function `foo` and*arguments passed to `bar`, than probably it like IFoo.

I think #1 is easier to understand once it is written. Thoughts?

Also construction*looks(Foo).like(IFoo) points direction of check. It youneed the two be replaceable you need two asserts:

assert looks(Foo).like(IFoo)
assert looks(IFoo).like(Foo)

Thanks.

Andriy Kornatskyy


----------------------------------------
> Date: Fri, 9 Nov 2012 17:14:49 +1100
> Subject: Re: duck typing assert
> From: rosuav@gmail.com
> To: python-list@python.org
>
> On Fri, Nov 9, 2012 at 12:00 PM, Ian Kelly <ian.g.kelly@gmail.com> wrote:
> > looks(Foo).like(IFoo), on the other hand, is crystal clear about which
> > argument is which.

>
> I'm not so sure that it is, tbh. If you read it like an English
> sentence, it's clearly testing whether Foo matches the template in
> IFoo, but which are you more likely to do: test one class to see if it
> satisfies lots of templates, or test one template against every class
> you meet? I think probably the latter is, if not more likely than the
> former, at least sufficiently plausible as to create confusion. It
> makes very good sense to say:
>
> duckmatch(IFoo).compare(Foo)
>
> ie with the arguments the other way.
>
> ChrisA
> --
> http://mail.python.org/mailman/listinfo/python-list


Steven D'Aprano 11-09-2012 01:36 PM

Re: duck typing assert
 
On Thu, 08 Nov 2012 18:00:58 -0700, Ian Kelly wrote:

> On Thu, Nov 8, 2012 at 4:33 PM, Steven D'Aprano
> <steve+comp.lang.python@pearwood.info> wrote:
>> On Thu, 08 Nov 2012 20:34:58 +0300, Andriy Kornatskyy wrote:
>>
>>> People who come from strongly typed languages that offer interfaces
>>> often are confused by lack of one in Python. Python, being dynamic
>>> typing programming language, follows duck typing principal. It can as
>>> simple as this:
>>>
>>> assert looks(Foo).like(IFoo)

>>
>> How very cute. And I don't mean that in a good way.
>>
>> Why is this a class with a method, instead of a function that takes two
>> class arguments (plus any optional arguments needed)?
>>
>> looks_like(Foo, IFoo)
>>
>> is less "cute", reads better to English speakers, and much more
>> Pythonic. This isn't Java, not everything needs to be a class.

>
> I disagree. Does that test whether Foo looks like IFoo, or IFoo looks
> like Foo?


What's the difference? "Looks like" is a symmetric comparison, like
"equal" and "almost equal", but not "subset", "less than" etc. If x looks
like y, then necessarily y must look like x. If Katy Perry looks like
Zooey Deschanel, then it stands to reason that Zooey Deschanel looks like
Katy Perry. James Woods looks like Erwin Schroedinger, and Erwin
Schroedinger looks like James Woods.

http://tvrefill.com/wp-content/uploa...-deschanel.jpg

http://cheezburger.com/6704400128


So in that sense, looks(Spam).like(Ham) must always be the same as
looks(Ham).like(Spam), and the order of operators doesn't matter.

But that's not what we want! And to his credit, that's not what Andriy
Kornatskyy's code actually implements. The problem is with the name,
which is actively misleading by suggesting a symmetrical comparison for
one which is not symmetrical.

Suppose we want to make a movie with Zooey Deschanel, but she's not
available, so we want a replacement who is duck-type compatible with her.
The replacement doesn't need to be a Deschanel sister, but she does need
to do *at least* everything Zooey can do. If she can do more, that's
fine, but she can't do less.

Since Katy Perry can do everything Zooey can do, PLUS she sings, we can
replace Zooey with Katy: Katy is duck-type compatible with Zooey. But we
can't replace Katy with Zooey, because Zooey can't sing.[1]

(I think... I really don't actually know if Zooey Deschanel can sing or
not. Just go along with the example.)

The point I am making is that "looks like" is not a good description for
this function. "Looks like" must be symmetrical, but the function we
actually want is not symmetrical. It is actually a "subset" type
relationship: given "looks(Zooey).like(Katy)", it checks that the public
methods etc. of Zooey are a subset of the methods of Katy. That is, that
instances of Katy can be used instead of instances of Zooey.

Or is it the other way? Damned if I know. Let's find out:

class Zooey:
def act(self): pass

class Katy:
def act(self): pass
def sing(self): pass


py> looks(Zooey).like(Katy)
__main__:2: UserWarning: 'sing': is missing.
False

I guessed wrong. The looks.like method as implemented tests that the
right-hand size operand is a subset of the right-hand-side:

py> looks(Katy).like(Zooey)
True


I argue that this is the wrong way around. (Even if it isn't the wrong
way around, it certainly isn't clear or obvious which way you have to
write the operands!)

Consider this use-case:

candidates = [Hilary, Jennifer, Katy]
expected = looks(Zooey) # instantiate the looks class once only
for actor in candidates:
if expected.like(actor):
make_movie_with(actor())


That's much nicer and more efficient than the way you have to write it
now:

candidates = [Hilary, Jennifer, Katy]
for actor in candidates:
# instantiate the looks class every time we want to test another class
if looks(actor).like(Zooey):
make_movie_with(actor())


So... it's a cute name, that sounds English-like. But it doesn't actually
describe what the function does, it is wasteful for at least one useful
use-case, and it's not clear which order you have to supply the two
arguments.


> looks(Foo).like(IFoo), on the other hand, is crystal clear about which
> argument is which.


I hope that by now you can see why I say that it is as clear as mud.





[1] Some people might argue that neither can Katy Perry.


--
Steven

Andriy Kornatskyy 11-09-2012 02:01 PM

RE: duck typing assert
 

1. In looks-like we check features of Foo (that may be superset) of what IFoo offers.

assert looks(Foo).like(IFoo)

2. We can check if Foo is limited to IFoo only:

assert looks(IFoo).like(Foo)

So it valid to have both asserts.

Thanks.

Andriy Kornatskyy


----------------------------------------
> From: steve+comp.lang.python@pearwood.info
> Subject: Re: duck typing assert
> Date: Fri, 9 Nov 2012 13:36:39 +0000
> To: python-list@python.org
>
> On Thu, 08 Nov 2012 18:00:58 -0700, Ian Kelly wrote:
>
> > On Thu, Nov 8, 2012 at 4:33 PM, Steven D'Aprano
> > <steve+comp.lang.python@pearwood.info> wrote:
> >> On Thu, 08 Nov 2012 20:34:58 +0300, Andriy Kornatskyy wrote:
> >>
> >>> People who come from strongly typed languages that offer interfaces
> >>> often are confused by lack of one in Python. Python, being dynamic
> >>> typing programming language, follows duck typing principal. It can as
> >>> simple as this:
> >>>
> >>> assert looks(Foo).like(IFoo)
> >>
> >> How very cute. And I don't mean that in a good way.
> >>
> >> Why is this a class with a method, instead of a function that takes two
> >> class arguments (plus any optional arguments needed)?
> >>
> >> looks_like(Foo, IFoo)
> >>
> >> is less "cute", reads better to English speakers, and much more
> >> Pythonic. This isn't Java, not everything needs to be a class.

> >
> > I disagree. Does that test whether Foo looks like IFoo, or IFoo looks
> > like Foo?

>
> What's the difference? "Looks like" is a symmetric comparison, like
> "equal" and "almost equal", but not "subset", "less than" etc. If x looks
> like y, then necessarily y must look like x. If Katy Perry looks like
> Zooey Deschanel, then it stands to reason that Zooey Deschanel looks like
> Katy Perry. James Woods looks like Erwin Schroedinger, and Erwin
> Schroedinger looks like James Woods.
>
> http://tvrefill.com/wp-content/uploa...-deschanel.jpg
>
> http://cheezburger.com/6704400128
>
>
> So in that sense, looks(Spam).like(Ham) must always be the same as
> looks(Ham).like(Spam), and the order of operators doesn't matter.
>
> But that's not what we want! And to his credit, that's not what Andriy
> Kornatskyy's code actually implements. The problem is with the name,
> which is actively misleading by suggesting a symmetrical comparison for
> one which is not symmetrical.
>
> Suppose we want to make a movie with Zooey Deschanel, but she's not
> available, so we want a replacement who is duck-type compatible with her.
> The replacement doesn't need to be a Deschanel sister, but she does need
> to do *at least* everything Zooey can do. If she can do more, that's
> fine, but she can't do less.
>
> Since Katy Perry can do everything Zooey can do, PLUS she sings, we can
> replace Zooey with Katy: Katy is duck-type compatible with Zooey. But we
> can't replace Katy with Zooey, because Zooey can't sing.[1]
>
> (I think... I really don't actually know if Zooey Deschanel can sing or
> not. Just go along with the example.)
>
> The point I am making is that "looks like" is not a good description for
> this function. "Looks like" must be symmetrical, but the function we
> actually want is not symmetrical. It is actually a "subset" type
> relationship: given "looks(Zooey).like(Katy)", it checks that the public
> methods etc. of Zooey are a subset of the methods of Katy. That is, that
> instances of Katy can be used instead of instances of Zooey.
>
> Or is it the other way? Damned if I know. Let's find out:
>
> class Zooey:
> def act(self): pass
>
> class Katy:
> def act(self): pass
> def sing(self): pass
>
>
> py> looks(Zooey).like(Katy)
> __main__:2: UserWarning: 'sing': is missing.
> False
>
> I guessed wrong. The looks.like method as implemented tests that the
> right-hand size operand is a subset of the right-hand-side:
>
> py> looks(Katy).like(Zooey)
> True
>
>
> I argue that this is the wrong way around. (Even if it isn't the wrong
> way around, it certainly isn't clear or obvious which way you have to
> write the operands!)
>
> Consider this use-case:
>
> candidates = [Hilary, Jennifer, Katy]
> expected = looks(Zooey) # instantiate the looks class once only
> for actor in candidates:
> if expected.like(actor):
> make_movie_with(actor())
>
>
> That's much nicer and more efficient than the way you have to write it
> now:
>
> candidates = [Hilary, Jennifer, Katy]
> for actor in candidates:
> # instantiate the looks class every time we want to test another class
> if looks(actor).like(Zooey):
> make_movie_with(actor())
>
>
> So... it's a cute name, that sounds English-like. But it doesn't actually
> describe what the function does, it is wasteful for at least one useful
> use-case, and it's not clear which order you have to supply the two
> arguments.
>
>
> > looks(Foo).like(IFoo), on the other hand, is crystal clear about which
> > argument is which.

>
> I hope that by now you can see why I say that it is as clear as mud.
>
>
>
>
>
> [1] Some people might argue that neither can Katy Perry.
>
>
> --
> Steven
> --
> http://mail.python.org/mailman/listinfo/python-list


Chris Angelico 11-09-2012 02:15 PM

Re: duck typing assert
 
On Sat, Nov 10, 2012 at 1:01 AM, Andriy Kornatskyy
<andriy.kornatskyy@live.com> wrote:
>
> 1. In looks-like we check features of Foo (that may be superset) of what IFoo offers.
>
> assert looks(Foo).like(IFoo)
>
> 2. We can check if Foo is limited to IFoo only:
>
> assert looks(IFoo).like(Foo)
>
> So it valid to have both asserts.


You'll almost never need #2, but since there's no difference between a
"class" and an "interface", it's perfectly legal to switch them
around.

But I would generally expect that unrecognized methods are never a
problem (assuming they don't collide with anything) - that, as in
Steven's example, it's fine to have an actor who can sing when you
don't need her to. When you post job openings, you don't normally ask
for someone with "5+ years Python experience and unable to program in
REXX" [1]. You're checking for a minimum set of requirements.

[1] Though I suppose you might ask for someone who's unable to program
in Pascal. Might save you some hassle.

ChrisA

Andriy Kornatskyy 11-09-2012 02:37 PM

RE: duck typing assert
 

There is sense for #2. Let me explain. There is basic IFoo implementation and improved Foo. While I switched to Foo, I still want to be as close to IFoo as possible, since there might be sense to switch to Foo2 later, which conform to IFoo.

Here is the problem: if I will not assert #2 potentially I will use some `features` that are not in IFoo, thus that breaks my code switching to Foo2later.

That might not apply for 100% usability cases, just wanted to point that out as reasonable thing.

Thanks.

Andriy Kornatskyy


----------------------------------------
> Date: Sat, 10 Nov 2012 01:15:36 +1100
> Subject: Re: duck typing assert
> From: rosuav@gmail.com
> To: python-list@python.org
>
> On Sat, Nov 10, 2012 at 1:01 AM, Andriy Kornatskyy
> <andriy.kornatskyy@live.com> wrote:
> >
> > 1. In looks-like we check features of Foo (that may be superset) of what IFoo offers.
> >
> > assert looks(Foo).like(IFoo)
> >
> > 2. We can check if Foo is limited to IFoo only:
> >
> > assert looks(IFoo).like(Foo)
> >
> > So it valid to have both asserts.

>
> You'll almost never need #2, but since there's no difference between a
> "class" and an "interface", it's perfectly legal to switch them
> around.
>
> But I would generally expect that unrecognized methods are never a
> problem (assuming they don't collide with anything) - that, as in
> Steven's example, it's fine to have an actor who can sing when you
> don't need her to. When you post job openings, you don't normally ask
> for someone with "5+ years Python experience and unable to program in
> REXX" [1]. You're checking for a minimum set of requirements.
>
> [1] Though I suppose you might ask for someone who's unable to program
> in Pascal. Might save you some hassle.
>
> ChrisA
> --
> http://mail.python.org/mailman/listinfo/python-list


Prasad, Ramit 11-09-2012 05:37 PM

RE: duck typing assert
 
Andriy Kornatskyy wrote:

>
> Thank you for all comments.
>

> > It*makes very good sense to say:
> >
> > duckmatch(IFoo).compare(Foo)

>
> Since we do duck match of IFoo...but there is no `duck match`, there is `duck test`.*I believe instead of
> `compare` is more readable with `equals`. Than it is more from*mathematics - precise answer...*that you can not
> guarantee at all in dynamic programming language. So it false to use such wordingto reflect this check. We can
> only make an assumption that one looks like the other (similar)... with some limitation of cause...
> understanding what is `duck test`.
>
> http://en.wikipedia.org/wiki/Duck_test
>
> The intent is to make such language `construct` so it reads as English sentence that make sense, and not
> mandatory `pythonic` way (readability counts, java smokes aside).
>
> is_similar(Foo).to(IFoo) # <= but we lost `duck test` sense here?
>
> Words `looks` and `like` are coming from duck test and point also direction:
>
> # 1
> looks(Foo).like(IFoo, notice=['__len__'], ignore_funcs=['foo'], ignore_argspec['bar'])
>
> English sentence equivalent: if functions in Foo looks like one in IFoo than, probably, IFoo can be replaced
> with Foo; notice to check __len__, it is safe to ignore function `foo` and arguments passed to `bar`.
>
> # 2
> looks(Foo, notice=['__len__'], ignore_funcs=['foo'], ignore_argspec['bar']).like(IFoo)
>
> English sentence equivalent:*while looking at Foo notice to check `__len__`, it is safe to ignore function `foo`
> and*arguments passed to `bar`, than probably it like IFoo.


What about?

duck(Foo).equivalent_to(IFoo, <kwargs>)
duck(Foo).matches(IFoo, <kwargs>)

This email is confidential and subject to important disclaimers and
conditions including on offers for the purchase or sale of
securities, accuracy and completeness of information, viruses,
confidentiality, legal privilege, and legal entity disclaimers,
available at http://www.jpmorgan.com/pages/disclosures/email.


All times are GMT. The time now is 04:42 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.