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

David MacQuigg dmq at gain.com
Sat May 1 11:47:00 EDT 2004


On 28 Apr 2004 02:20:06 -0700, michele.simionato at poste.it (Michele
Simionato) wrote:

>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.

This is amazing! I don't understand how it works, but it does provide
what I think the "classless" advocates are looking for, an ability to
"clone" one object from another, and avoid any "two-tier" organization
of instances and classes.

>>> cat3 = cat1("Fluffy", "Purr")   # Make a new cat from a previous.
>>> cat3.talk()
My name is Fluffy
I am a Feline from Earth
Feline talking: Purr!

It is a shame that the discussion has degenerated to the point where
most people are ignoring threads relating to prototypes.  I have tried
repeatedly to get a simple requirements statement or use case, and get
nothing but sarcastic remarks.  I have no experience with prototype
languages either, except a little with Prothon.  I started to read a
paper, but fell asleep after a discussion on the "theory of
knowledge".

In spite of all this, there are some nuggets along the way.  The
unification of methods and functions is the one I am most interested
in.  The code below seems to have the machinery to do that, with the
elimination of 'self' from the argument list.  That alllows static
methods to have exactly the same form as normal methods. ( The 'show'
methods below are actually static methods if you remove any references
to 'self', and replace them with explicit references, i.e.
self.numAnimals --> Animal.numAnimals ).

I agree with you that Python has the capability to implement
prototypes.  Perhaps we can do that using metaclasses for some initial
experiments.  Then if we get some constructive feedback, we can put
together a PEP to make prototypes part of the core language, add
better syntax, and fix whatever might not work quite right using
metaclasses.

I'm collecting ideas for Python 3 and 4 and putting them on my webpage
at http://ece.arizona.edu/~edatools/Python  Python 3 includes features
that are not compatible with Python 2, but I believe are consistent to
the extent that Python 2 programs can be automatically translated to
Python 3.  Python 4 has no such contraint.  All that matters is that
the language is simple and elegant, and does useful things, as opposed
to things that are theoretically interesting.  Your comments and
suggestions are welcome.

-- Dave

>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