Getting lazy with decorators

Peter Otten __peter__ at web.de
Sun Jun 24 04:07:45 EDT 2012


Josh English wrote:
> I'm creating a cmd.Cmd class, and I have developed a helper method to
> easily handle help_xxx methods.
>> I'm trying to figure out if there is an even lazier way I could do this
> with decorators.
>> Here is the code:
> *********************
> import cmd
>>> def add_help(func):
> if not hasattr(func, 'im_class'):
> return func #probably should raise an error
> cls = func.im_class
> setattr(cls, func.im_func.__name__.replace("do","help"), None)
>> return func
>>> class BaseCmd(cmd.Cmd):
> def __init__(self, *args, **kwargs):
> cmd.Cmd.__init__(self, *args, **kwargs)
>> def show_help(self, func):
> print "\n".join((line.strip() for line in
> func.__doc__.splitlines()))
>> @add_help
> def do_done(self, line):
> """done
> Quits this and goes to higher level or quits the application.
> I mean, what else do you expect?
> """
> return True
>> if __name__=='__main__':
> c = BaseCmd()
>> print c.help_done
>>> *********************
>> This generates "AttributeError: BaseCmd instance has no attribute
> 'help_done'"
>> The show_help method is the shortcut I want to use (I'm pretty sure it's
> from Doug Hellman's site). I'm wondering if it's possible to use a
> decorator such as add_help to automatically create the appropriate
> help_xxx function.
>> In the decorator, I can get the function and the name of the class, but I
> can't find the instance of the class that the method is attached to.
> Maybe this is just one step of lazy too far.
>>> Am I right in thinking that I can't do this? There is no way to access the
> class instance from the method?

You cannot access a class instance because even the class itself doesn't 
exist yet. You could get hold of the class namespace with sys._getframe(),
def add_help(f):
 exec """\
def help_%s(self):
 f = getattr(self, %r)
 self.show_help(f)
""" % (f.__name__[3:], f.__name__) in sys._getframe(1).f_locals
 return f
but here's a simpler approach:
import cmd
def add_help(f):
 def help(self):
 self.show_help(f)
 f.help = help
 return f
class BaseCmd(cmd.Cmd):
 def __init__(self, *args, **kwargs):
 cmd.Cmd.__init__(self, *args, **kwargs)
 def show_help(self, func):
 print "\n".join((line.strip() for line in 
func.__doc__.splitlines()))
 def __getattr__(self, name):
 if name.startswith("help_"):
 helpfunc = getattr(self, "do_" + name[5:]).help
 setattr(self.__class__, name, helpfunc)
 return getattr(self, name)
 raise AttributeError
 @add_help
 def do_done(self, line):
 """done
 Quits this and goes to higher level or quits the application.
 I mean, what else do you expect?
 """
 return True
if __name__=='__main__':
 c = BaseCmd()
 c.cmdloop()


More information about the Python-list mailing list

AltStyle によって変換されたページ (->オリジナル) /