metaclass and customization with parameters
Alex Martelli
aleaxit at yahoo.com
Sun Oct 3 04:27:15 EDT 2004
zipher <zondervanz at gmail.com> wrote:
> After searching through comp.lang.python and the web regarding
> metaclasses, I could not find an example for customing classes using
> metaclass parameters.
When a class statement executes, Python determines the metaclass (e.g.
by finding a '__metaclass__' attribute in the class body) and then calls
it with three parameters -- never more, never fewer:
class name(bases):
__metaclass__ = metaboo
...rest of class body snipped...
is exactly equivalent to:
name = metaboo('name', bases, d)
where 'd' is the dict that remains after execution of the class body
(all barenames bound in the body -- be that by def, class, assignment,
import, whatever -- are left as entries in that 'd').
> I want to be able to create a class at runtime by calling some
All classes are created at runtime, normally by executing (at runtime:
there is no other 'time'...;-) a 'class' statement.
> function or 'meta-constructor' which returns a customized class and
> sets a class attribute according a given parameter.
>
> Ideally, I'd be able to do something like:
>
> >>> Bag = Metadict(filter=int) #Metadict returns a new class named
> 'Bag'
The normal Python syntax for that purpose might rather be:
class Bag:
__metaclass__ = Metadict
filter = int
and for that use, Medadict would be rather simple to write... but
your stated purpose (to this point) is even better accomplished by:
class Bag(dict):
filter = int
> >>> issubclass(Bag, dict) # which is a type of dict
> True
> >>> Bag.filter # with class attribute set accordingly
> <type 'int'>
> >>> b = Bag({'pennies': 6.0, 'dimes': 3}) #create instances of this
> new class
>
> (Aside: the issue of magically knowing the variable name (i.e. 'Bag')
> in that first assignment statement and setting the class name
> accordingly would be ideal, but I could live with passing the name as
> a parameter to Metadict if necessary.)
If you want to explicitly call Metadict as a factory, rather than use a
'class' statement, yep, there is then no way in which Metadict can know
what name its result will be bound to, so you'd have to pass it. But
why isn't a class statement even better?
> There would also be a number of new and re-defined methods which would
> be part of all classes constructed and returned by calls to Metadict.
> For example, somewhere I need to re-define dict's __setitem__ method
> to something like:
>
> >>> def __setitem__(self, key, value):
> ... self[key] = self.filter(value) #coerce/validate values before
> adding to dict
>
> Ideally, all such methods would be in their own class definition since
> they will be common to all classes created by Metadict (perhaps they
> would need be defined within Metadict itself).
No, this is best done by inheritance:
class Bag(filtered_dict):
filter = int
with, e.g:
class filtered_dict(dict):
def __setitem__(self, key, value):
dict.__setitem__(self, key, self.filter(value))
> This seems like a simple thing to want, but unusally convoluted to
> actually implement. I'm not even sure where to start.
>
> Any pointers?
I would start with inheritance, because I don't see what value a custom
metaclass would add; indeed I see only downsides, such as needing to
pass the intended class name, if you want to use explicit-call syntax.
If it does turn out that subclasses of filtered_dict all DO need a
custom metaclass, for reasons connected to specs you haven't yet
mentioned, just add the metaclass (with a __metaclass__ in the body) to
filtered_dict, and every subclass thereof will inherit it. That's all
there is to it... class statement, and inheritance, appear to give you
all that you have required/explained so far, except the kind of syntax
you deem ideal (but is really second best, due to the need to pass a
class name...).
Alex
More information about the Python-list
mailing list