[Tutor] associating two objects without ORM and processing a text file

Alan Gauld alan.gauld at btinternet.com
Tue Feb 12 00:16:40 CET 2013

On 11/02/13 22:49, neubyr wrote:

> is right approach to implement 'list_by_author' function as a class
> method is typically used as an alternative constructor.

Not at all that is only one use case for class methods.
A class method is *any* method that operates on the whole class of 
objects - i.e. all instances(potentially including those still to be 

Now I agree that in some lanmguages they tend to be limited to factory 
metjods(eg Objective C implicitly goes that way) but in others  like 
Smalltalk search methods and persistence etc are often found as class 
methods. In Python, because of it's hybrid nature, these are often 
"demoted" to global scope functions.

> Here I am
> returning list of objects and not just an object.

Which is to say a subset of the class Book.
Therefore quite reasonably a class method.

>    @classmethod
>    def list_by_author(self,author):
>      """ Return list of books of an author """
>      bookfile = config.bookfile
>      books = [] # empty list - used as list of Books
>      # TODO: improve regex
>      regex = re.compile(author)
>      with open (bookfile,'r') as f:
>        for line in f:
>          if regex.findall(line):
>            # error prone - if name contains comma
>            l = line.split(',')
>            # create book object and append it to a list
>            book = self(*l)
>            books.append(book)
>      return books # return list of books

I'd probably, for a small dataset, load a list of books into the class 
at startup and save it at termination. Which makes the search code 
easier and potentially can be data driven so you pass the filter 
attribute as a parameter. You can then use getattr() to find the value:

def findBooks(cls, param, value):
     return [book for book in books if getattr(book, param) == value]

You could make it more flexible still by defining the filter as a 
function and passing a lambda:

def findBooks(cls, filterExp):
     return [book for book in books if filterExp(book)]

Usage example:

DickensBooks = Book.findBook(lambda b: 'Dickens' in b.author)

Of course if you have a huge dataset then that won't work - which brings 
us back to a database :-)


Alan G
Author of the Learn to Program web site

More information about the Tutor mailing list