Re: [Tutor] instance method call issue
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
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
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
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
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