Re: [Tutor] instance method call issue

2012-10-21 Thread Steven D'Aprano

Digging up a week-old email from Bob:


On 15/10/12 08:37, bob gailer wrote:

On 10/14/2012 8:34 AM, Osemeka Osuagwu wrote:

except:
print 'Cannot display Grid'


In addition to Steve's comment I add my own gripe:

When delivering an error message tell us WHY. I have seen too many
messages "cannot do xxx" with no information that might help me
debug.
"cannot load file xxx"
"Windows cannot load the installer for xxx"

or totally confusing messages
"error 6 trying to report error 6"
"cannot do xxx to file yyy. file exists"

In reality the underlying program knows a lot more about why. Could
not the developers have presented that information as well?



Of course they can, and I always try to write good, helpful error
messages. Sometimes I fail :)

Here is a random selection of some of my exceptions, taken entirely
out of context:

ValueError('error tolerances must be non-negative')
StatsError('geometric mean of negative number')
InvalidNumber("Invalid TFN, checkdigit does not match.")
ValueError('output file already exists')
TypeError('frange expects 1-4 arguments, got %d' % n)
ValueError('step must not be zero')
ValueError('gamma function undefined at 0 and negative integers')
TypeError('expected a namespace but got a %s' % typename)
TypeError('abstract method <%s> must be overridden' % func.__name__)


And then there's this one...

ValueError("broken")


O_o


--
Steven
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] instance method call issue

2012-10-14 Thread bob gailer

On 10/14/2012 8:34 AM, Osemeka Osuagwu wrote:

 except:
 print 'Cannot display Grid'

In addition to Steve's comment I add my own gripe:

When delivering an error message tell us WHY. I have seen too many 
messages "cannot do xxx" with no information that might help me debug.

"cannot load file xxx"
"Windows cannot load the installer for xxx"

or totally confusing messages
"error 6 trying to report error 6"
"cannot do xxx to file yyy. file exists"

In reality the underlying program knows a lot more about why. Could not 
the developers have presented that information as well?


--
Bob Gailer
919-636-4239
Chapel Hill NC

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] instance method call issue

2012-10-14 Thread Alan Gauld

On 14/10/12 13:34, Osemeka Osuagwu wrote:


I understand instance, static and class methods but I'm still
struggling with when and where they should be used.


You can pretty much ignore static methods, they were almost an
historic 'accident' superseded, in most cases, by class methods. The 
number of cases where a staticmethod is really needed is very low.


class methods you will rarely need but they are used when you want to do 
something to the entire class of objects. i.e. something that affects 
all instances both existing and future. Or they could be used where 
there are no instances (yet). Factory methods, instance selection

methods, modifying shared attributes, instance pooling, are all
examples. To give some kind of heuristic based on my personal usage, I 
use class methods in almost all my bigger projects. Such a project might 
have 20 or 30 (or more) classes. Out of that maybe 2 or 3 will have any 
class methods.


Instance methods are by far the most common. These are the things you 
want to do to a specific instance of the class. Changes to one instance 
have no effect on other instances of the same class.



In the code below, I can't seem to get around calling an instance
method (__reality_check()) from within a class method (update_grid()),


It's not a class method, you want to update a specific instance of a 
grid. update_grids() might be a class method if you wanted to, say,
change the maximum buffer size used to store the grids, or cause all 
grids to display the word 'empty' instead of a blank. Of course to do 
that you would need access to all the instances to update their existing 
values so the constructor would need to store a reference to itself in 
the class somewhere (or maybe in a separate shared database).
The class method would then iterate over all instances calling their 
instance method update_grid(). This is a common(*) class method pattern,

where a plural class method calls the singular instance methods
of all the instances.

(*) I say common, but of course class methods are not common
so its a very relative term!

HTH

--
Alan G
Author of the Learn to Program web site
http://www.alan-g.me.uk/

___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor


Re: [Tutor] instance method call issue

2012-10-14 Thread Steven D'Aprano

On 14/10/12 23:34, Osemeka Osuagwu wrote:


In the code below, I can't seem to get around calling an instance
method (__reality_check()) from within a class method (update_grid()),


Of course you can't :)

Since the class method has no access to the instance, it cannot call
instance methods, since it doesn't know which instance to use!

Instead, update_grid needs to be an instance method. Of course it
does! It needs to update a specific grid, right? That will be the
instance.



I'm not even too sure that update_grid() should have been a class
method in the first place.



Probably not. Static and class methods are rarely used, since they have
no access to the instance that owns them.

Class methods are generally used for alternate constructor functions, e.g.
dict.fromkeys. Since it makes no difference whether you call fromkeys
from the class (dict) or from an instance, it is made a classmethod.

Static methods, well, 99 times out of a hundred if you think you want to
use a static method, you're probably better off making it a module level
function.

By my count, there are over 26000 instance methods in the Python standard
library, 202 class methods, and only 84 static methods. So they are rare.
I've been using Python for about 15 years, and I think I could count the
number of times I've used staticmethod on the fingers of one hand.




Please, I need help with this and any other advice on my coding style,
where I could've been more efficient etc.


class Grid:
 '''Grid(rows = 26, columns = 26) ->  Provides a world object
for the cells in Game of Life'''
 from time import sleep
 from os import system
 from sys import platform


Move the imports outside of the class. They should go at the start of
the module.

As written, your class has attributes Grid.sleep, Grid.system, etc. Since
these attributes have nothing to do with Grids, they don't belong in the
Grid class. Move them out.

Classes are not catch-all collections of unrelated methods. That's
what modules are for :)





 #class data:
 __rows, __array, os_type = [''], [], platform


A word of advise: don't waste your time with double underscore "private"
attributes. They're no more private than single underscore (private by
convention only), and the name mangling can cause difficulty when
debugging.

There are good reasons for using double underscores like this, but you
should consider them a bit more advanced.



 @staticmethod
 def display_grid(generation, os_type):
 try:
 (lambda x:Grid.system('cls') if 'win' in
os_type else Grid.system('clear'))(1)



That's wrong! Your display_grid method uses the class (Grid), so it
shouldn't be a static method.

Move the imports to the module level, and display_grid as a regular
function:

def display_grid(generation, array):
clear_screen()
print 'Now in Generation %d' % generation
for line in array:
print line

def clear_screen(platform=sys.platform()):
# The default here is set once, and defaults to your platform.
if 'win' in platform:
command = 'cls'
else:
command = 'clear'
os.system(command)


Or leave display_grid as an instance method:


class Grid:
def display_grid(self, generation):
clear_screen()
print 'Now in Generation %d' % generation
for line in self._array:
print line


Either way, clear_screen has nothing to do with grids, so it should
not be a method of Grid.




 except:
 print 'Cannot display Grid'


Never use a bare except like that. Bare except should *only* be used
at the interactive interpreter, for lazy people who want to avoid
typing. It should never be used non-interactively, it's simply poor
practice.

The problem with bare excepts is that they cover up too much. Your aim
is to write code that works. If it has a bug, you need to *see* the bug
so you can identify it and then fix it. Bare excepts make bugs
invisible.




 @staticmethod
 def extend_grid(thickness = 4, force_extend = False):
 '''extend_grid([thickness][, force_extend]) -->
Extends the edges of the grid by 4 units in
all directions if the boundary of the simulation comes close to the
edge. Extends anyway if force_extend option is True'''


Why is this a static method?

Which grid is this operating on? It should either take a grid as an
argument, or extend_grid should be an instance method that operates
on itself:

# either this top-level function
def extend_grid(grid, thickness=4, force=False):
# do stuff to the grid to extend it
# and then return it
return grid


# or make this a regular instance method
class Grid:
def extend_grid(self, thickness=4, force=False):
# do stuff to self to extend it
# no need to return anything




 @classmethod
 def update_grid(cls, generations, speed):



Why is this a class method?



   

[Tutor] instance method call issue

2012-10-14 Thread Osemeka Osuagwu
Hello people,
Firstly, thank you so much for all the assistance you provide so
selflessly through this medium.
I come from a functional programming background and have only recently
become serious with OOP.
For practice, I tried to implement John Conways 'Game of Life' without
a GUI and ran into some issues.
I understand instance, static and class methods but I'm still
struggling with when and where they should be used.
In the code below, I can't seem to get around calling an instance
method (__reality_check()) from within a class method (update_grid()),
I'm not even too sure that update_grid() should have been a class
method in the first place.
Please, I need help with this and any other advice on my coding style,
where I could've been more efficient etc.


class Grid:
'''Grid(rows = 26, columns = 26) -> Provides a world object
for the cells in Game of Life'''
from time import sleep
from os import system
from sys import platform

#class data:
__rows, __array, os_type = [''], [], platform

@staticmethod
def display_grid(generation, os_type):
try:
(lambda x:Grid.system('cls') if 'win' in
os_type else Grid.system('clear'))(1)
except:
print 'Cannot display Grid'
print 'Now in Generation %d' %(generation)
for line in Grid.__array:
print line
return

@staticmethod
def extend_grid(thickness = 4, force_extend = False):
'''extend_grid([thickness][, force_extend]) -->
Extends the edges of the grid by 4 units in
all directions if the boundary of the simulation comes close to the
edge. Extends anyway if force_extend option is True'''
pass
return

@classmethod
def update_grid(cls, generations, speed):
'''Runs the 'Life' World simulation for the specified
number of generations at the given speed'''
#control = input
#while
for times in range(generations + 1):
cls.extend_grid()
cls.__reality_check(Grid, 'all')
cls.display_grid(times, cls.os_type)
cls.sleep(speed)
return

#--

def __init__(self, rows = 26, col = 26):
'''Create a 'rows' x 'col' grid'''
Grid.__rows *= rows
Grid.__array = [Grid.__rows] * col
print 'A %d x %d cell World has been Created' %(rows, col)

def __reality_check(self, num = 'all'):
'''__reality_check([num]) -->Checks and updates the
state of the cell based on the number of 'alive' neighbors'''

#check if reality check is for single cell or entire array
if num == 'all':
for i in range(len(Grid.__array)):
for j in range(len(Grid.__array[i])):
self.__reality_check((i,j))
return

#Neighbor count check and update for single cell(num = row, col)
elif num == tuple and len(num) == 2:
col, row, neighbor_count = num[1], num[0], 0
for x in range(row-1, row+2):
for y in range(col-1, col+2):
#count only 'alive' neighbors
(includes the subject cell itself)
neighbor_count = lambda x: x+1
if Grid.__array[x][y] == '##' else x
#correct the neighbor count value if subject
cell was counted
neighbor_count = lambda x: x-1 if
Grid.__array[row][col] == '##' else x

#update cell(x,y) state
Grid.__array[row][col] = lambda x:'##' if
neighbor_count == 3 else ''

else:
print 'Wrong argument for reality check'
return

def edit_cell(self, cells, state = '##'):
'''edit_cell(cells[, state]) --> Where cells is a list
of tuples containing coordinates of the cells to edit'''
cells = cells
for eachcell in cells:
Grid.__array[eachcell[0]][eachcell[1]] = state
return

#To be moved to a different .py file after debugging.
world = Grid()
world.edit_cell([(10,10), (10, 11), (10, 12), (11, 10)], '##')
world.update_grid(5, 0.5)



p.s. I'm not yet completely through with coding some aspects like the
extend_grid() method'

Thank you
Abasiemeka
___
Tutor maillist  -  Tutor@python.org
To unsubscribe or change subscription options:
http://mail.python.org/mailman/listinfo/tutor