Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.python > #7095 > unrolled thread

Re: Lambda question

Started byTerry Reedy <tjreedy@udel.edu>
First post2011-06-06 12:52 -0400
Last post2011-06-06 19:00 -0500
Articles 4 — 4 participants

Back to article view | Back to comp.lang.python

This discussion starts older than the indexed window; earlier articles aren't shown. The article labeled Started by below is the oldest one visible, not the original post.


Contents

  Re: Lambda question Terry Reedy <tjreedy@udel.edu> - 2011-06-06 12:52 -0400
    Re: Lambda question Steven D'Aprano <steve+comp.lang.python@pearwood.info> - 2011-06-06 23:16 +0000
      API design before implementation (was: Lambda question) Ben Finney <ben+python@benfinney.id.au> - 2011-06-07 09:54 +1000
      Re: Lambda question harrismh777 <harrismh777@charter.net> - 2011-06-06 19:00 -0500

#7095 — Re: Lambda question

FromTerry Reedy <tjreedy@udel.edu>
Date2011-06-06 12:52 -0400
SubjectRe: Lambda question
Message-ID<mailman.2494.1307379170.9059.python-list@python.org>
On 6/6/2011 9:42 AM, jyoung79@kc.rr.com wrote:
>>>>>> f = lambda x, n, acc=[]: f(x[n:], n, acc+[(x[:n])]) if x else acc
>
>> Packing tail recursion into one line is bad for both understanding and
>> refactoring. Use better names and a docstring gives
>>
>> def group(seq, n):
>>     'Yield from seq successive disjoint slices of length n plus the
>> remainder'
>>     for i in range(0,len(seq), n):
>>       yield seq[i:i+n]

[I added back the last 'n' that got deleted somehow]

> Thank you all very much for this incredible help!  The original code
> now makes sense, and I was thrilled to see better and more efficient
> ways of doing this.  Thanks for taking the time to share your
> thoughts as well as the excellent detail everyone shared…  I really
> appreciate it!

You are welcome.

Let me add something not said much here about designing functions: start 
with both a clear and succinct definition *and* test cases. (I only 
started writing tests first a year ago or so.) Test cases help test the 
definition statement as well as the yet-to-be-written code. They also 
make re-factoring much safer. I think test cases should start with null 
inputs. For this function:

for inn,out in (
         (('',1), []), # no input, no output
         (('abc',0), []), # definition unclear, could be error
         (('abc',1), ['a','b','c']),
         (('abcd',2), ['ab','cd']),
         (('abcde',2), ['ab', 'cd', 'e']), # could change this
         ):
     assert list(group(*inn)) == out, (inn,out)

This fails with
ValueError: range() arg 3 must not be zero

I will let you think about and try out what the original code 'f=../ 
does with n=0. It is not good. A third problem with lambda expressions 
is no test for bad inputs. They were added to Python for situations 
where one needs a function as an argument and and the return expression 
is self-explanatory, clearly correct, and safe for any inputs it could 
get in the context it is passed into. For example, lambda x: 2*x.

This works:

def group(seq, n):
   'Yield from seq successive disjoint slices of length n & the remainder'
   if n<=0: raise ValueError('group size must be positive')
   for i in range(0,len(seq), n):
     yield seq[i:i+n]

for inn,out in (
         (('',1), []), # no input, no output
         #(('abc',0), ValueError), # group size positive
         (('abc',1), ['a','b','c']),
         (('abcd',2), ['ab','cd']),
         (('abcde',2), ['ab', 'cd', 'e']), # could change this
         ):
     assert list(group(*inn)) == out, (inn,out)

I have written a function test function that I will post or upload to 
PyPI sometime. It accepts i/o pairs with error 'outputs', like the one 
commented out above.

-- 
Terry Jan Reedy

[toc] | [next] | [standalone]


#7115

FromSteven D'Aprano <steve+comp.lang.python@pearwood.info>
Date2011-06-06 23:16 +0000
Message-ID<4ded5fda$0$29996$c3e8da3$5496439d@news.astraweb.com>
In reply to#7095
On Mon, 06 Jun 2011 12:52:31 -0400, Terry Reedy wrote:

> Let me add something not said much here about designing functions: start
> with both a clear and succinct definition *and* test cases. (I only
> started writing tests first a year ago or so.)


For any non-trivial function, I usually start by writing the 
documentation (a docstring and doctests) first. How else do you know what 
the function is supposed to do if you don't have it documented?

By writing the documentation and examples before the code, I often 
discover that the API I first thought of was rubbish :)


-- 
Steven

[toc] | [prev] | [next] | [standalone]


#7118 — API design before implementation (was: Lambda question)

FromBen Finney <ben+python@benfinney.id.au>
Date2011-06-07 09:54 +1000
SubjectAPI design before implementation (was: Lambda question)
Message-ID<874o42348c.fsf_-_@benfinney.id.au>
In reply to#7115
Steven D'Aprano <steve+comp.lang.python@pearwood.info> writes:

> On Mon, 06 Jun 2011 12:52:31 -0400, Terry Reedy wrote:
>
> > Let me add something not said much here about designing functions: start
> > with both a clear and succinct definition *and* test cases. (I only
> > started writing tests first a year ago or so.)
>
> For any non-trivial function, I usually start by writing the
> documentation (a docstring and doctests) first. How else do you know
> what the function is supposed to do if you don't have it documented?

By trying to use it. At least, that's my approach: figure out what I
want the function to do by pretending it already exists, and write some
code that expects it to work.

Sometimes that code is a test case (in which case I'm doing test-first
development). Other times I'm not sure what I *want* the function to do
yet, so I'm also experimenting with what the interface should be (in
which case I'm doing something closer to a “spike implementation”).


All of that also stops me from writing the function until I can think of
a descriptive name for the function, and a docstring synopsis: the first
line of the docstring, a self-contained sentence saying what the
function is for. The synopsis should be exactly one short line; see PEP
257.

Once I know the function signature (parameters and return value), then I
write the docstring body.

> By writing the documentation and examples before the code, I often 
> discover that the API I first thought of was rubbish :)

Yep. That's also a big benefit of designing code by pretending it
exists, I find.

Fred Brooks tells us that we should plan from the beginning to throw one
away; because we will, anyhow. You and I seem to have ways to invest as
little as possible in the first design before throwing it away :-)

-- 
 \       “Are you pondering what I'm pondering?” “Umm, I think so, Don |
  `\          Cerebro, but, umm, why would Sophia Loren do a musical?” |
_o__)                                           —_Pinky and The Brain_ |
Ben Finney

[toc] | [prev] | [next] | [standalone]


#7119

Fromharrismh777 <harrismh777@charter.net>
Date2011-06-06 19:00 -0500
Message-ID<fSdHp.1437$xh5.1370@newsfe02.iad>
In reply to#7115
Steven D'Aprano wrote:
> For any non-trivial function, I usually start by writing the
> documentation (a docstring and doctests) first. How else do you know what
> the function is supposed to do if you don't have it documented?

Yes. In my early years I was no different than any other hacker in terms 
of documenting last if at all... but having flown around the sun a few 
more times I've realized that good clear doc 'before' the code actually 
helps me write good clean code. If I implement what I've documented then 
I'm less likely to miss something in the doc, and more likely to have 
fewer bugs... this has played itself out many times for me.



kind regards,
m harris

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.python


csiph-web