Registry of Methods via Decorators

Bruno Desthuilliers onurb at xiludom.gro
Thu Jun 22 10:36:00 EDT 2006


bayerj wrote:
> I want to make a registry of methods of a class during creation. My
> attempt was this
> 
> """ classdecorators.py
> 
> Author: Justin Bayer
> Creation Date: 2006-06-22
> Copyright (c) 2006 Chess Pattern Soft,
> All rights reserved.  """
> 
> class decorated(object):
> 
>     methods = []
> 
>     @classmethod
>     def collect_methods(cls, method):
>         cls.methods.append(method.__name__)
>         return method
> 
> class dec2(decorated):
> 
>     @collect_methods
>     def first_func(self):
>         pass
> 
>     @collect_methods
>     def second_func(self):
>         pass
> 
> 
> def main():
>     print dec2.methods
> 
> if __name__ == '__main__':
>     main()
> 
> This does not work and exits with "NameError: ("name 'collect_methods'
> is not defined",)". Which is understandable due to the fact that the
> class dec2 is not complete.
> 
> Anyone can give me a hint how to work around this?

If you insist on doing black-magic (else go directly to the end of this
post), here's a way to do it, based on Ian Bicking's __classinit__ recipe
http://blog.ianbicking.org/a-conservative-metaclass.html

(BTW, Ian, many many thanks for this trick - I really love it).

class DeclarativeMeta(type):
    def __new__(meta, class_name, bases, new_attrs):
        cls = type.__new__(meta, class_name, bases, new_attrs)
        cls.__classinit__.im_func(cls, new_attrs)
        return cls
class Declarative(object):
    __metaclass__ = DeclarativeMeta
    def __classinit__(cls, new_attrs): pass

class MethodCollector(Declarative):
    def __classinit__(cls, new_attrs):
        cls.methods = [name for name, attr in new_attrs.items() \
                       if callable(attr)]

class dec2(MethodCollector):
    def first_func(self):
        pass

    def second_func(self):
        pass


If you want to choose which methods to collect, then it's just a matter
of adding a simple decorator and a test in MethodCollector.__classinit__:

def collect(func):
  func._collected = True
  return func


class MethodCollector(Declarative):
    def __classinit__(cls, new_attrs):
        cls.methods = [name for name, attr in new_attrs.items() \
                       if callable(attr) \
                       and getattr(attr, '_collected', False)]

class dec2(MethodCollector):
    @collect
    def first_func(self):
        pass

    @collect
    def second_func(self):
        pass

    def not_collected(self):
        pass



*BUT* is it really useful to go thru all this mess ?

class DeadSimple(object):
    @classmethod
    def methods(cls):
        return [name for name in dir(cls) \
                if not name.startswith('__') \
                and callable(getattr(cls, name))]


My 2 cents...
-- 
bruno desthuilliers
python -c "print '@'.join(['.'.join([w[::-1] for w in p.split('.')]) for
p in 'onurb at xiludom.gro'.split('@')])"



More information about the Python-list mailing list