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