Re: [Tutor] don't repeat yourself; question about code optimization CORRECTION

2007-07-29 Thread tpc247
On 7/23/07, Bob Gailer [EMAIL PROTECTED] wrote:

 A correction to the code at the end. The test of self.total_num_of_items
 should precede the pop(0)



Bob, I spent today studying what you've been telling me and I put the
finishing touches to make your code pass my battery of tests.  It still is
repetitive, i.e., table.append(tuple(row)), but I've found guidance in what
Alan had to say about code readability and easy maintenance, and am no
longer going to press the matter:

class Table_Creator(object):
def __init__(self, total_num_of_items, max_num_of_items_per_row):
self.given_items = range(total_num_of_items)
self.max_num_of_items_per_row = max_num_of_items_per_row

def create_grid(self):
table = []
while True:
row = []
while len(row)  self.max_num_of_items_per_row:
if not self.given_items:
if row:
table.append(tuple(row))
return table
row.append(self.given_items.pop(0))
table.append(tuple(row))
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization

2007-07-29 Thread tpc247
On 7/23/07, Alan Gauld [EMAIL PROTECTED] wrote:


 The prime directive of coding is make it readable!
 The DRY principle is just that a principle. If repeating makes for
 more maintainable or readable code then repeat yourself.

 Remember 80% of the cost of software is in maintenance not initial
 development. DRY is one way to improve maintainablility
 PS The most serious problem with your code from my perpspective
 is that your variable names are way too long. That affects maintenance
 and readability more that the repetition (and in the case of email it
 causes line wrapping that makes it even worse!)

 Finally the class is not a good class in an OOP sense since it is
 nearly a verb.
 It is better done as a simple function in my view, just pass in the
 parameters to
 the create method. Like this:

 def create_table(num_items, row_size):
 start = 0
 table = []
 num_rows = num_items/row_size
 for n in range(num_rows):
 row = [num for num in range(start,start+row_size)]
 table.append(tuple(row))
 start += row_size
 return table

 Or better still build a table class that knows how to create
 itself, but also knows how to maniplulate itself too - doing whatever
 it is you intend doing to the table you just created! This reflects
 another
 programming rule - the law of demeter - one of the fundamentals of
 OOP.



Alan, I spent today going over what you took the time to patiently
illustrate to me, and I believe I learned the following things:
- code readability and ease of maintenance are the primary goals of a
computer programmer
- classes that are very nearly verbs should be converted to functions,
unless you can write a class that knows how to create and manipulate itself,
following the law of demeter

About the last bit of code, where you propose to create the table using list
comprehension, I did want to capture partial rows, so I put the finishing
touches to your work so it could.  When I subjected the code to a battery of
tests, it failed in the following way:

def create_table(num_items, row_size):
start = 0
table = []
num_rows = (num_items/row_size) + (num_items%row_size)
for n in range(num_rows):
row = [num for num in range(num_items)[start:start+row_size]]
table.append(tuple(row))
start += row_size
return table

def test_harness():
assert create_table(3, 1) == [(0,), (1,), (2,)]
assert create_table(4, 1) == [(0,), (1,), (2,), (3,)]
assert create_table(1, 2) == [(0,)]
assert create_table(2, 2) == [(0, 1)]
assert create_table(4, 2) == [(0, 1), (2, 3)]
assert create_table(5, 2) == [(0, 1), (2, 3), (4, )]
assert create_table(5, 3) == [(0, 1, 2), (3, 4)]
assert create_table(7, 4) == [(0, 1, 2, 3), (4, 5, 6)]

assert create_table(5, 3) == [(0, 1, 2), (3, 4)]
AssertionError

I know that my method of calculating the number of rows is faulty, but I'm
not sure how to correct it.
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization CORRECTION

2007-07-29 Thread Eric Brunson
[EMAIL PROTECTED] wrote:


 On 7/23/07, *Bob Gailer* [EMAIL PROTECTED] 
 mailto:[EMAIL PROTECTED] wrote:

 A correction to the code at the end. The test of
 self.total_num_of_items
 should precede the pop(0)



 Bob, I spent today studying what you've been telling me and I put the 
 finishing touches to make your code pass my battery of tests.  It 
 still is repetitive, i.e., table.append(tuple(row)),

I see you're also repeating the use of = quite a bit, as well as 
multiple uses of the word if.  Maybe you could work on that.

Sorry for the sarcasm, but there's a big different between repeating an 
assignment and a type coersion versus a multi line block of code that 
could be converted to a function.  :-)

 but I've found guidance in what Alan had to say about code readability 
 and easy maintenance, and am no longer going to press the matter:

 class Table_Creator(object):
 def __init__(self, total_num_of_items, max_num_of_items_per_row):
 self.given_items = range(total_num_of_items)
 self.max_num_of_items_per_row = max_num_of_items_per_row

 def create_grid(self):
 table = []
 while True:
 row = []
 while len(row)  self.max_num_of_items_per_row:
 if not self.given_items:
 if row:
 table.append(tuple(row))
 return table
 row.append(self.given_items.pop(0))
 table.append(tuple(row))
  


 

 ___
 Tutor maillist  -  Tutor@python.org
 http://mail.python.org/mailman/listinfo/tutor
   

___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization

2007-07-29 Thread ALAN GAULD
 assert create_table(5, 3) == [(0, 1, 2), (3, 4)]
 AssertionError

 I know that my method of calculating the number of rows is faulty, 
 but I'm not sure how to correct it.




num_rows = (num_items/row_size) + (num_items%row_size)


This uses integer division then adds the remainder, so for your 
example of 5,3 we get



5/3 = 1

5%3 = 2

So rows = 3 -  wrong!



All you want to do is add one if the modulus is not zero, so



num_rows = (num_items/row_size) 

if num_items % row_size  0: 

num_rows += 1



Should do what you want. 



HTH,



Alan G.














___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization CORRECTION

2007-07-29 Thread Bob Gailer
[EMAIL PROTECTED] wrote:


 On 7/23/07, *Bob Gailer* [EMAIL PROTECTED] 
 mailto:[EMAIL PROTECTED] wrote:

 A correction to the code at the end. The test of
 self.total_num_of_items
 should precede the pop(0)



 Bob, I spent today studying what you've been telling me and I put the 
 finishing touches to make your code pass my battery of tests.  It 
 still is repetitive, i.e., table.append(tuple(row)), but I've found 
 guidance in what Alan had to say about code readability and easy 
 maintenance, and am no longer going to press the matter:

 class Table_Creator(object):
 def __init__(self, total_num_of_items, max_num_of_items_per_row):
 self.given_items = range(total_num_of_items)
 self.max_num_of_items_per_row = max_num_of_items_per_row

 def create_grid(self):
 table = []
 while True:
 row = []
 while len(row)  self.max_num_of_items_per_row:
 if not self.given_items:
 if row:
 table.append(tuple(row))
 return table
 row.append(self.given_items.pop(0))
 table.append(tuple(row))
A bit more juggling leads to more simplification:

def create_grid(self):
table = []
while self.given_items:
row = []
while len(row)  self.max_num_of_items_per_row and 
self.given_items:
row.append(self.given_items.pop(0))
table.append(tuple(row))
return table

Testing self.given_items twice is unavoidable.

-- 
Bob Gailer
510-978-4454 Oakland, CA
919-636-4239 Chapel Hill, NC


___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization

2007-07-23 Thread tpc247

On 7/20/07, Bob Gailer [EMAIL PROTECTED] wrote:


Take advantage of slicing:
   def create_grid(self):
   table = []
   for i in range(0, len(self.total_num_of_items),
self.max_num_of_items_per_row):
 table.append(tuple(self.total_num_of_items[i : i +
self.max_num_of_items_per_row]))
   return table



simply amazing.  Thank you.

OK - to address your original question:


def create_grid(self):
table = []
while self.total_num_of_items:
row = []
count = 0
while count  self.max_num_of_items_per_row and
self.total_num_of_items:
row.append(self.total_num_of_items.pop(0))
count += 1
table.append(tuple(row))
return table



At first I  regarded you with quiet awe, but then the nitpick in me saw the
two while self.total_num_of_item statements, and I was less pleased.
However, I see this as a doable challenge you have given me, and I will
attempt to optimize your revisions.  Thanks again.
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization

2007-07-23 Thread Alan Gauld
[EMAIL PROTECTED] wrote

 one part where I believe I violate the prime directive of coding, 
 which is
 not to repeat yourself:

The prime directive of coding is make it readable!
The DRY principle is just that a principle. If repeating makes for
more maintainable or readable code then repeat yourself.

Getting too hung up on a catchy acronym is a dangerous
thing IMHO. It can lead to too much effort going into satisfying
the principle and not enough into thinking about the problem at
hand and how the code will be maintained.

Remember 80% of the cost of software is in maintenance not initial
development. DRY is one way to improve maintainablility and that's
its purpose - to avoid having to fix things in two places - but it is 
not
a rule that must be slavishly followed at the expense of
readability/maintainability. It's in the same category as
Do not use GOTO,
Do not use global variables,
Functions should be less than 25 lines long

These are all useful principles which usually improve code quality
but there are exceptions in every case.

Now in your example removing repetition will improve things slightly,
but I am always concerned when I see terms like prime directive of
coding being applied to something like DRY.

PS The most serious problem with your code from my perpspective
is that your variable names are way too long. That affects maintenance
and readability more that the repetition (and in the case of email it
causes line wrapping that makes it even worse!) The names are
also not accurate of their function, for example total_num_of_items
is not a number at all but a list of numbers...

I'd therefore suggest a rewrite of your init method like:

def __init__(self, num_of_items, max_per_row):
self.numbers = range(num_of_items)
self.max_per_row = max_per_row

And the modified create method looks like:

def create_grid(self):
table = []
row = []
count = 0
while self.numbers:
row.append(self.numbers.pop(0))
count += 1
 if (not self.numbers) or (count == self.max_per_row):
table.append(tuple(row))
row = []
count = 0
return table

Which makes the indentation error more obvious...

The use of a while loop here could be replaced by a Python
for loop which eliminates your repetition and is more natural:

def create_grid(self):
table = []
row = []
for number in self.numbers:
row.append(number)
if len(row) == self.max_per_row:
   table.append(tuple(row))
   row = []
if len(row) != 0   # not sure if you want partially completed 
rows or not
   table.append(tuple(row))
return table

However, since you are in effect trying to create a list of lists
I suggest a combination of list comprehension and slicing would be
a better solution.

def create_grid(self):
start = 0
table = []
num_rows = len(self.numbers)/max_per_row# this should 
really be in init!
for n in range(num_rows):
row = [num for num in 
self.numbers[start:start+self.max_per_row]]
table.append(row)
start += self.max_per_row
return table

Which happens to meet the DRY principle. But we got there, not by 
trying
to avoid DRY but by improving the algorithm and structure of the code.
DRY was merely a side efffect.

Finally the class is not a good class in an OOP sense since it is 
nearly a verb.
It is better done as a simple function in my view, just pass in the 
parameters to
the create method. Like this:

def create_table(num_items, row_size):
start = 0
table = []
num_rows = num_items/row_size
for n in range(num_rows):
row = [num for num in range(start,start+row_size)]
table.append(tuple(row))
start += row_size
return table

Or better still build a table class that knows how to create
itself, but also knows how to maniplulate itself too - doing whatever
it is you intend doing to the table you just created! This reflects 
another
programming rule - the law of demeter - one of the fundamentals of 
OOP.

-- 
Alan Gauld
Author of the Learn to Program web site
http://www.freenetpages.co.uk/hp/alan.gauld 


___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization

2007-07-23 Thread Bob Gailer
[EMAIL PROTECTED] wrote:


 On 7/20/07, *Bob Gailer* [EMAIL PROTECTED] 
 mailto:[EMAIL PROTECTED] wrote:

 Take advantage of slicing:
def create_grid(self):
table = []
for i in range(0, len( self.total_num_of_items),
 self.max_num_of_items_per_row):
  table.append(tuple(self.total_num_of_items[i : i +
 self.max_num_of_items_per_row ]))
return table


 simply amazing.  Thank you.
One of the many shifts one makes in adjusting to new language 
features. I made such a shift in 1974 when I switched from FORTRAN and 
PL/I to APL.

 OK - to address your original question:

 def create_grid(self):
 table = []
 while self.total_num_of_items:
 row = []
 count = 0
 while count  self.max_num_of_items_per_row and
 self.total_num_of_items:
 row.append(self.total_num_of_items.pop(0))
 count += 1
 table.append(tuple(row))
 return table


 At first I  regarded you with quiet awe
We gurus bask in attention.
 , but then the nitpick in me saw the two while 
 self.total_num_of_item statements, and I was less pleased.
Oh all right, that costs us one more statement. Independently we can get 
rid of count:

def create_grid(self):
table = []
while True:
row = []
while len(row)  self.max_num_of_items_per_row:
row.append(self.total_num_of_items.pop(0))
if not self.total_num_of_items:
return table
table.append(tuple(row))


-- 
Bob Gailer
510-978-4454 Oakland, CA
919-636-4239 Chapel Hill, NC


___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization CORRECTION

2007-07-23 Thread Bob Gailer
A correction to the code at the end. The test of self.total_num_of_items 
should precede the pop(0)

[EMAIL PROTECTED] wrote:


 On 7/20/07, *Bob Gailer* [EMAIL PROTECTED] 
 mailto:[EMAIL PROTECTED] wrote:

 Take advantage of slicing:
def create_grid(self):
table = []
for i in range(0, len( self.total_num_of_items),
 self.max_num_of_items_per_row):
  table.append(tuple(self.total_num_of_items[i : i +
 self.max_num_of_items_per_row ]))
return table


 simply amazing.  Thank you.
One of the many shifts one makes in adjusting to new language
features. I made such a shift in 1974 when I switched from FORTRAN and
PL/I to APL.

 OK - to address your original question:

 def create_grid(self):
 table = []
 while self.total_num_of_items:
 row = []
 count = 0
 while count  self.max_num_of_items_per_row and
 self.total_num_of_items:
 row.append(self.total_num_of_items.pop(0))
 count += 1
 table.append(tuple(row))
 return table


 At first I  regarded you with quiet awe
We gurus bask in attention.
 , but then the nitpick in me saw the two while 
 self.total_num_of_item statements, and I was less pleased.
Oh all right, that costs us one more statement. Independently we can get
rid of count:

def create_grid(self):
table = []
while True:
row = []
while len(row)  self.max_num_of_items_per_row:
if not self.total_num_of_items:
return table
row.append(self.total_num_of_items.pop(0))
table.append(tuple(row))


-- 
Bob Gailer
510-978-4454 Oakland, CA
919-636-4239 Chapel Hill, NC



___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


[Tutor] don't repeat yourself; question about code optimization

2007-07-20 Thread tpc247

dear fellow Python enthusiasts:

in the last year I have been experimenting with Python, and I set out to
create a function that, given a number of items and a maximum number of
items per row, would generate a table of rows of items.  However, there is
one part where I believe I violate the prime directive of coding, which is
not to repeat yourself:

class Table_Creator(object):
   def __init__(self, given_num_of_items, max_num_of_items_per_row):
   self.total_num_of_items = range(given_num_of_items)
   self.max_num_of_items_per_row = max_num_of_items_per_row

   def create_grid(self):
   table = []
   row = []
   count = 0
   while self.total_num_of_items:
   row.append(self.total_num_of_items.pop(0))
   count += 1
   if (not self.total_num_of_items) or (count ==
self.max_num_of_items_per_row):
   table.append(tuple(row))
   row = []
   count = 0
   return table

as you can see, I repeat the expressions row = [] and count = 0, and I
would like to know if there is something I can do to avoid repetition in
this case.
___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization

2007-07-20 Thread Bob Gailer
[EMAIL PROTECTED] wrote:
 dear fellow Python enthusiasts:

 in the last year I have been experimenting with Python, and I set out 
 to create a function that, given a number of items and a maximum 
 number of items per row, would generate a table of rows of items.  
 However, there is one part where I believe I violate the prime 
 directive of coding, which is not to repeat yourself:

 class Table_Creator(object):
 def __init__(self, given_num_of_items, max_num_of_items_per_row):
 self.total_num_of_items = range(given_num_of_items)
 self.max_num_of_items_per_row = max_num_of_items_per_row

 def create_grid(self):
 table = []
 row = []
 count = 0
 while self.total_num_of_items:
 row.append(self.total_num_of_items.pop(0))
 count += 1
 if (not self.total_num_of_items) or (count == 
 self.max_num_of_items_per_row):
 table.append(tuple(row))
 row = []
 count = 0
 return table

 as you can see, I repeat the expressions row = [] and count = 0, 
 and I would like to know if there is something I can do to avoid 
 repetition in this case.
First fix the indentation of the line starting with if.

-- 
Bob Gailer
510-978-4454 Oakland, CA
919-636-4239 Chapel Hill, NC


___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization

2007-07-20 Thread Bob Gailer
[EMAIL PROTECTED] wrote:
 dear fellow Python enthusiasts:

 in the last year I have been experimenting with Python, and I set out 
 to create a function that, given a number of items and a maximum 
 number of items per row, would generate a table of rows of items.  
 However, there is one part where I believe I violate the prime 
 directive of coding, which is not to repeat yourself:

 class Table_Creator(object):
 def __init__(self, given_num_of_items, max_num_of_items_per_row):
 self.total_num_of_items = range(given_num_of_items)
 self.max_num_of_items_per_row = max_num_of_items_per_row

 def create_grid(self):
 table = []
 row = []
 count = 0
 while self.total_num_of_items:
 row.append(self.total_num_of_items.pop(0))
 count += 1
 if (not self.total_num_of_items) or (count == 
 self.max_num_of_items_per_row):
 table.append(tuple(row))
 row = []
 count = 0
 return table

 as you can see, I repeat the expressions row = [] and count = 0, 
 and I would like to know if there is something I can do to avoid 
 repetition in this case.
OK - to address your original question:

def create_grid(self):
table = []
while self.total_num_of_items:
row = []
count = 0
while count  self.max_num_of_items_per_row and 
self.total_num_of_items:
row.append(self.total_num_of_items.pop(0))
count += 1
table.append(tuple(row))
return table


-- 
Bob Gailer
510-978-4454 Oakland, CA
919-636-4239 Chapel Hill, NC


___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] don't repeat yourself; question about code optimization

2007-07-20 Thread Bob Gailer
[EMAIL PROTECTED] wrote:
 dear fellow Python enthusiasts:

 in the last year I have been experimenting with Python, and I set out 
 to create a function that, given a number of items and a maximum 
 number of items per row, would generate a table of rows of items.  
 However, there is one part where I believe I violate the prime 
 directive of coding, which is not to repeat yourself:

 class Table_Creator(object):
 def __init__(self, given_num_of_items, max_num_of_items_per_row):
 self.total_num_of_items = range(given_num_of_items)
 self.max_num_of_items_per_row = max_num_of_items_per_row

 def create_grid(self):
 table = []
 row = []
 count = 0
 while self.total_num_of_items:
 row.append(self.total_num_of_items.pop(0))
 count += 1
 if (not self.total_num_of_items) or (count == 
 self.max_num_of_items_per_row):
 table.append(tuple(row))
 row = []
 count = 0
 return table

 as you can see, I repeat the expressions row = [] and count = 0, 
 and I would like to know if there is something I can do to avoid 
 repetition in this case.
Take advantage of slicing:
def create_grid(self):
table = []
for i in range(0, len(self.total_num_of_items), 
self.max_num_of_items_per_row):
  table.append(tuple(self.total_num_of_items[i : i + 
self.max_num_of_items_per_row]))
return table


-- 
Bob Gailer
510-978-4454 Oakland, CA
919-636-4239 Chapel Hill, NC


___
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor