Closures in metaclasses
Arnaud Delobelle
arnodel at googlemail.com
Thu Jan 21 14:10:07 EST 2010
On Jan 21, 6:37 pm, Falcolas <garri... at gmail.com> wrote:
> On Jan 21, 11:24 am, Arnaud Delobelle <arno... at googlemail.com> wrote:
>
>
>
>
>
> > Falcolas <garri... at gmail.com> writes:
> > > I'm running into an issue with closures in metaclasses - that is, if I
> > > create a function with a closure in a metaclass, the closure appears
> > > to be lost when I access the final class. I end up getting the text
> > > 'param' instead of the actual tags I am expecting:
>
> > > ALL_TAGS = ['a', 'abbr', 'acronym', 'address', 'applet', 'b', 'bdo',
> > > 'big'] #snip
>
> > > def _tag_meta(name, bases, dict_):
> > > for tag in ALL_TAGS:
> > > def generic_tag(*args, **kwargs):
> > > return Tag._generate_tag(tag, *args, **kwargs)
> > > #generic_tag = eval("lambda *args, **kwargs: Tag._generate_tag
> > > ('%s', *args, **kwargs)" % tag)
> > > dict_[tag] = staticmethod(generic_tag)
> > > return type(name, bases, dict_)
>
> > This is almost a FAQ and has nothing to do with metaclasses. The
> > simplest solution usually involves adding a default argument 'tag=tag'
> > to the function you define (here, generic_tag), but you can't do this
> > here because you have a **kwargs argument. Instead, you can use a
> > closure and do this for example:
>
> > def factory(tag):
> > def generic_tag(*args, **kwargs):
> > return Tag._generate_tag(tag, *args, **kwargs)
> > return generic_tag
>
> > def _tag_meta(name, bases, dict_):
> > for tag in ALL_TAGS:
> > dict_[tag] = staticmethod(factory(tag))
> > return type(name, bases, dict_)
>
> I see - I was thinking it would preserve the closure from the for
> statement, but I can see now why that would be wrong.
>
>
>
> > However, I am usure about why you are using a metaclass.
>
> > HTH
>
> > --
> > Arnaud
>
> It was the easiest way I found to add a lot of static methods to the
> Tag class without writing each one out. __getattr__ was not working
> for this application. This is for a very simple application, and I
> didn't want to add a lot of complexity to it's use. I'm always open
> for other options OTOH.
This should work (untested):
class Tag(object):
@staticmethod
def _generate_tag(tag_name, *args, **kwargs):
# Does the expected, following is just for the example's sake
return tag
for tag in ALL_TAGS:
setattr(Tag, tag, staticmethod(factory(tag)))
Or you could override __getattr__
--
Arnaud
More information about the Python-list
mailing list