Re: exec and closures
On Feb 22, 3:18 am, Peter Otten <[EMAIL PROTECTED]> wrote: > Alejandro Dubrovsky wrote: > > def autoassign(_init_): > > import inspect > > import functools > > > argnames, _, _, defaults = inspect.getargspec(_init_) > > argnames = argnames[1:] > > > indentation = '' > > settings = ['self.%s = %s' % (arg[1:], arg) for arg in argnames > > if arg[0] == '_'] > > > if len(settings) <= 0: > > return _init_ > > > if defaults is None: > > args = argnames[:] > > else: > > args = argnames[:-len(defaults)] > > for key, value in zip(argnames[-len(defaults):],defaults): > > args.append('%s=%s' % (key, repr(value))) > > > template = """def _autoassign(self, %(args)s): > > %(setting)s > > _init_(self, %(argnames)s) > > """ % {'args' : ", ".join(args), 'setting' : "\n".join(['%s%s' % > > (indentation, setting) for setting > > in settings]), 'argnames' : ', '.join(argnames)} > > > try: > > exec template > > except SyntaxError, e: > > raise SyntaxError('%s. line: %s. offset %s:\n%s' % > > (e.msg, e.lineno, e.offset, template)) > > return _autoassign > > [snip] > > Is there a way to bind the _init_ name at exec time? > > Use a dedicated namespace: > > namespace = dict(_init_=_init_) > exec template in namespace > return namespace["_autoassign"] > > Peter That works! Excellent, thanks. I still don't understand why the original doesn't work. I thought exec with no namespace specified used the current context, in which _init_ would be _init_ already. But understanding can wait. ale -- http://mail.python.org/mailman/listinfo/python-list
Re: exec and closures
Alejandro Dubrovsky wrote: > About a month ago, there was a thread on auto-assigning decorators for > __init__. One by André Roberge is here: > http://groups.google.com/group/comp.lang.python/browse_frm/ > thread/32b421bbe6caaeed/0bcd17b1fa4fb07c?#0bcd17b1fa4fb07c > > This works well for simple cases, but doesn't take keyword arguments or > set default values. I wrote a more extensive version implementing python > call semantics, but it seemed awkard to be repeating something the > compiler does already, so I tried execing a function definition on the > fly with the right parameters that would function as the decorator. Like > this (adjust the indentation variable if it throws a syntax error) > > def autoassign(_init_): > import inspect > import functools > > argnames, _, _, defaults = inspect.getargspec(_init_) > argnames = argnames[1:] > > indentation = '' > settings = ['self.%s = %s' % (arg[1:], arg) for arg in argnames > if arg[0] == '_'] > > if len(settings) <= 0: > return _init_ > > if defaults is None: > args = argnames[:] > else: > args = argnames[:-len(defaults)] > for key, value in zip(argnames[-len(defaults):],defaults): > args.append('%s=%s' % (key, repr(value))) > > template = """def _autoassign(self, %(args)s): > %(setting)s > _init_(self, %(argnames)s) > """ % {'args' : ", ".join(args), 'setting' : "\n".join(['%s%s' % > (indentation, setting) for setting > in settings]), 'argnames' : ', '.join(argnames)} > > try: > exec template > except SyntaxError, e: > raise SyntaxError('%s. line: %s. offset %s:\n%s' % > (e.msg, e.lineno, e.offset, template)) > return _autoassign > > > Which creates what looked like the right template, but when instantiating > a class that uses that (eg > class A(object): > @autoassign > def __init__(self,_a): > pass > a = A(3) > > it throws a > NameError: global name '_init_' is not defined > > Is there a way to bind the _init_ name at exec time? Use a dedicated namespace: namespace = dict(_init_=_init_) exec template in namespace return namespace["_autoassign"] Peter -- http://mail.python.org/mailman/listinfo/python-list
exec and closures
About a month ago, there was a thread on auto-assigning decorators for __init__. One by André Roberge is here: http://groups.google.com/group/comp.lang.python/browse_frm/ thread/32b421bbe6caaeed/0bcd17b1fa4fb07c?#0bcd17b1fa4fb07c This works well for simple cases, but doesn't take keyword arguments or set default values. I wrote a more extensive version implementing python call semantics, but it seemed awkard to be repeating something the compiler does already, so I tried execing a function definition on the fly with the right parameters that would function as the decorator. Like this (adjust the indentation variable if it throws a syntax error) def autoassign(_init_): import inspect import functools argnames, _, _, defaults = inspect.getargspec(_init_) argnames = argnames[1:] indentation = '' settings = ['self.%s = %s' % (arg[1:], arg) for arg in argnames if arg[0] == '_'] if len(settings) <= 0: return _init_ if defaults is None: args = argnames[:] else: args = argnames[:-len(defaults)] for key, value in zip(argnames[-len(defaults):],defaults): args.append('%s=%s' % (key, repr(value))) template = """def _autoassign(self, %(args)s): %(setting)s _init_(self, %(argnames)s) """ % {'args' : ", ".join(args), 'setting' : "\n".join(['%s%s' % (indentation, setting) for setting in settings]), 'argnames' : ', '.join(argnames)} try: exec template except SyntaxError, e: raise SyntaxError('%s. line: %s. offset %s:\n%s' % (e.msg, e.lineno, e.offset, template)) return _autoassign Which creates what looked like the right template, but when instantiating a class that uses that (eg class A(object): @autoassign def __init__(self,_a): pass a = A(3) it throws a NameError: global name '_init_' is not defined Is there a way to bind the _init_ name at exec time? Thanks, ale -- http://mail.python.org/mailman/listinfo/python-list