Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.python > #7095 > unrolled thread
| Started by | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| First post | 2011-06-06 12:52 -0400 |
| Last post | 2011-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.
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
| From | Terry Reedy <tjreedy@udel.edu> |
|---|---|
| Date | 2011-06-06 12:52 -0400 |
| Subject | Re: 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]
| From | Steven D'Aprano <steve+comp.lang.python@pearwood.info> |
|---|---|
| Date | 2011-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]
| From | Ben Finney <ben+python@benfinney.id.au> |
|---|---|
| Date | 2011-06-07 09:54 +1000 |
| Subject | API 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]
| From | harrismh777 <harrismh777@charter.net> |
|---|---|
| Date | 2011-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