AntiDecorator metaclass

Paul Morrow pm_mon at yahoo.com
Fri Aug 13 23:21:53 EDT 2004


One of the beautiful things about Python is its clear, minimal syntax. 
So we must resist adding new syntax to the language, especially where 
there is a reasonable alternative.

I believe that Stefen Eischet's suggestion for automatically determining 
a method's type (class/instance/static) from the name of its first 
formal parameter is a reasonable alternative to any/all of the decorator 
syntax proposals.

Just as the Python system relies on indentation conventions to denote 
the programmer's intended block structure, it could just as well rely on 
parameter naming conventions to denote method types.  And as long as 
these conventions feel natural to the programmer, the language retains 
its beauty.

So here is a metaclass that illustrates (what I believe is) the 
essential idea behind Stefen's suggestion.  See the docstring and 
footnotes for a description of what it does.

##################################################################
class AntiDecorator(type):
     """ Metaclass that protests against decorator syntax :-)

     This metaclass infers a method's method type (instance, class,
     or static) from the name of its first formal parameter, then
     makes the necessary Python declaration.

     * If the 1st parm's name is 'self', then the method is
     an instance method.

     * If the 1st parm's name is 'cls' or 'klass', then the
     method is a class method.

     * All other methods are static methods.

     -------------------------------------------------
     The essence of this technique was suggested by
     Stefan Eischet on the comp.lang.python newsgroup.
     -------------------------------------------------

     This is freeware, no warranties, etc...

     """
     __author__ = 'Paul Morrow <pm_mon at yahoo.com>'
     __credits__ = 'Stefen Eischet <stefan at eischet.com>'
     __date__ = '13 Aug 04'
     __version__ = '0.1'

     def __new__(cls, clsName, bases, dict):
         import inspect, types
         for fName in dict.keys():
             f = dict[fName]                               # 1.
             if type(f) is types.FunctionType:             # 2.
                 parmNames = inspect.getargspec(f)[0]      # 3.
                 if parmNames:                             # 4.
                     if parmNames[0] in ('cls', 'klass'):  # 5.
                         dict[fName] = classmethod(f)
                     elif parmNames[0] == 'self':          # 6.
                         pass
                     else:                                 # 7.
                         dict[fName] = staticmethod(f)
                 else:		                          # 8.
                     dict[fName] = staticmethod(f)
         return type.__new__(cls, clsName, bases, dict)
         """Footnotes:
             1. Bind f to an attribute of the class (cls).
             2. Only work this magic on functions.
             3. Get the function's formal parameter names.
             4. If it has formal parameters, we'll use them
                 to determine what kind of function it is.
             5. It's a class method if its first formal
                 parameter is 'cls' or 'klass'.
             6. It's an instance method (default) if its first
                 formal parm is 'self'
             7. It's a static method if it's not a class method
                 or instance method.
             8. No formal parameters, so it's a static method.
         """

class Object(object):
     """ Uses AntiDecorator metaclass to infer method type. """
     __metaclass__ = AntiDecorator

if __name__ == '__main__':
     class Foo(Object):
         def imethod(self, parm):
             print "I'm an instance method: %s." % parm
         def cmethod(cls, parm):
             n = cls.__name__
             print "I'm a class method (of %s): %s." % (n, parm)
         def smethod(parm):
             print "I'm a static method: %s." % parm

     Foo().imethod('alpha')
     Foo.smethod('beta')
     Foo.cmethod('gamma')
##################################################################




More information about the Python-list mailing list