prototypes in Python [was: what is good in Prothon]

Michele Simionato michele.simionato at poste.it
Wed Apr 28 05:20:06 EDT 2004


So far, I have not installed Prothon, nor I have experience with Io, Self
or other prototype-based languages. Still, from the discussion on the 
mailing list, I have got the strong impression that you do not actually
need to fork Python in order to implement prototypes. It seems to me
that Python metaclasses + descriptors are more than powerful enough to 
implementing prototypes in pure Python.

I wrote a module that implements part of what David MacQuigg discussed in
http://apache.ece.arizona.edu/~edatools/Python/Prototypes.htm in few lines 
of code (disclaimer: this is an horrible hack that changes Python semantics 
and makes "super" and "self" kinda of implicit reserved 
keywords, highly unpythonic). It requires Python 2.2+.
I have not read the whole David MacQuigg's document, nor I have done any 
serious testing of the module, nor I claim I do understand what prototypes 
are; also I guarantee there will be bugs and surprising behaviors, but
still I think they could be fixed if I was willing to spend more time
on the issue.

Here is an example of usage:

from prototype import Prototype # prototypes are implemented as classes

class Animal(Prototype):  
    numAnimals = 0
    home = "Earth"
    def __init__(): # no need to pass self around
        Animal.numAnimals += 1
    def show():  
        print "Animals:", self.numAnimals

class Feline(Animal):
    genus="Feline"
    def __init__(name,sound): # no need to pass self around
        super.__init__()
        self.name=name
        self.sound=sound
    def talk(): # no need to pass self around
        print "%s talking: %s!" % (self.genus,self.sound)
        
class Cat(Feline): # how to call the super prototype
    numCats = 0
    def __init__ ( n = "unknown", s = "Meow" ):
        super.__init__(n,s)
        Cat.numCats += 1
    def show():
        super.show()
        print "    Cats:", self.numCats
    def talk():
        print "My name is", self.name
        print "I am a %s from %s" % (self.genus, self.home)
        super.talk()
      
cat1 = Cat() # abuse of notation: makes a new prototype, not an instance

print cat1 # =>
# <class '__main__.Prototype:Cat'>

cat2 = Cat("Garfield")
cat2.home = "Tucson"

print cat2 # =>
# <class '__main__.Prototype:Cat'>

cat1.talk() # =>
# My name is unknown
# I am a Feline from Earth
# Feline talking: Meow!

cat2.talk()# =>
# My name is Garfield
# I am a Feline from Tucson
# Feline talking: Meow!

cat2.show() # =>
# Animals: 2
#    Cats: 2

I am not sure this does what prototype people wants, but still it is 
a nice example of how to abuse Python ;) Originally, I tried to use
"_" for "self" and "__" for "super", but with my fonts it was
difficult to distinguish between them. With a preprocessor one
could replace .name -> self.name and ..name -> super.name, but
I did no bother to do that. 

Here is the module (not at all optimized):

$ cat prototype.py
import sys
from types import FunctionType
from inspect import isfunction

class methodwrapper(object): # descriptor
    def __init__(self,func,cls):
        self.__func__=func
        self.__cls__=cls
    def __get__(self,none,cls):
        globs=sys.modules[cls.__module__].__dict__.copy()
        globs["self"]=cls
        globs["super"]=super(self.__cls__,cls)
        return FunctionType(
            self.__func__.func_code,
            globs,
            self.__func__.func_name,
            self.__func__.func_defaults,
            self.__func__.func_closure)

class _Prototype(type): # metaclass
    def __init__(cls,name,bases,dic):
        for k,v in dic.iteritems():
            if isfunction(v):
                setattr(cls,k,methodwrapper(v,cls))
        super(_Prototype,cls).__init__(name,bases,dic)
    def __call__(cls,*args,**kw):
        newcls = type("Prototype:%s" % cls.__name__,(cls,),
                      {"__module__": cls.__module__}) 
        newcls.__init__(*args,**kw)
        return newcls

class Prototype(object): # mother of all prototypes
    __metaclass__=_Prototype
    def __init__(*args,**kw):
        pass

#### END ####

                   Michele Simionato



More information about the Python-list mailing list