AntiDecorator metaclass

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


Paul Morrow wrote:

> 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')
> ##################################################################
> 

Rats!  Please forgive my careless mispellings of Stefan's name.

Pual





More information about the Python-list mailing list