[Tutor] Adding voting to several object in python and db
Danny Yoo
dyoo at hkn.eecs.berkeley.edu
Sun Oct 29 02:34:31 CET 2006
> Ok now to my question, I m trying to add a ranking feature to various
> objects in the system, the users, their posts, their media etc, suffice
> to say I have to rank a lot of objects.
Hi Anil,
It sounds like you want to add some sort of feature to a heterogeneous set
of classes. Traditionally, you could use a design pattern like
"decorator" do to do this. Another way to add some feature to several
different classes is to use multiple inheritance.
Python's classes give us another tool in our toolbox called "mixins".
The idea is that we can systematically build new classes with enhanced
behavior in a cookie-cutter way. Here's a concrete example:
############################################
_counter = 0
def makeAutoincrementingClass(superClass):
class NewClass(superClass):
def __init__(self, *args, **kwargs):
global _counter
superClass.__init__(self, *args, **kwargs)
self.__id = _counter
_counter = _counter + 1
def id(self):
return self.__id
return NewClass
############################################
This is something that should look really weird at first!
makeAutoincrementingClass() is a function that takes in a superClass, and
returns a new class. Let's try using it:
##################################################
>>> class Candy:
... def __init__(self, name):
... self.name = name
... def __str__(self):
... return "%s" % self.name
...
>>> CountedCandy = makeAutoincrementingClass(Candy)
>>> c = CountedCandy("reeses")
>>> c.id()
0
>>> print c
reeses
>>> g = CountedCandy("gumdrops")
>>> g.id()
1
####################################################
So here we've added some auto-incrementing id assignment to Candy.
That's sorta cool. But we can add auto-incrementing behavior to any
preexisting class:
##########################################################
>>> from StringIO import StringIO
>>> StringIO
<class StringIO.StringIO at 0x76240>
>>> CountedStringIO = makeAutoincrementingClass(StringIO)
>>> s1 = CountedStringIO("hello world, this is a test")
>>> s2 = CountedStringIO("happy halloween")
>>> s1.id()
2
>>> s2.id()
3
>>> s2.read(5)
'happy'
##########################################################
Now we've added this id-allocating behavior to a class from the Standard
Library. Cool stuff.
> I cant but woefully look at Ruby_oN_rails guys adding ranking with just
> one line @act_as_votable and they are set.. no more bugs to fix, Do you
> guys have any ideas on how to do this, somehting similar to
My recommendatio is to really get functions down cold. They are much more
powerful than you might guess. What the Ruby folks are doing when they
define @act_as_votable is pretty much a mixin technique, just in different
syntax. (And Python has this syntax in the form of "decorators".) The
idea that drives this is that one can write functions from classes to
classes, and it's a neat idea.
There was a very old article about this in:
http://www.linuxjournal.com/node/4540/print
where they implement mixins with some __bases__ hackery. Personally, I
don't like their approach of mutating the input class. So the example I
wrote above does not mess with the existing class:
makeAutoincrementingClass derives a new class that doesn't interfere.
Best of wishes!
More information about the Tutor
mailing list