Inheritable Slots Metaclass

Carl Banks pavlovevidence at gmail.com
Wed May 26 16:50:37 EDT 2010


On May 26, 5:49 am, Rebel Lion <r38311... at gmail.com> wrote:
> I made a metaclass to inherit __slots__ automatically.
>
> I think this feature should be included in builtin object's metaclass.

I'd be ok with a metatype in the standard library that makes slots
more transparent, but since slots are intended as an optimization, it
doesn't really need (and might be detrimental to have) transparency
for ordinary objects.

However, Aahz will be by shortly to tell you never to use slots.

> You can now write:
>
>     class Foo(object):
>         __metaclass__ = SlotMetaclass
>
>         @slot
>         def foo():
>             pass
>
>     class Bar(Foo):
>
>         @slot
>         def bar():
>             pass
>
>     foo = Foo()
>     foo.foo = 1
>     bar = Bar()
>     bar.bar = 1
>     bar.foo = 1
>     try:
>         bar.baz = 1 # this should fall
>     except AttributeError, e:
>         print 'yeah', e
>
> Instead of
>
>     class Foo(object):
>           __slots__ = ['foo']
>     class Bar(Foo)
>           __slots__ = ['foo', 'bar']
>
> Please discuss the pros & cons for this feature.

It seems like a good approach, but the use of decorators to define
slots is hideous.  I'd recommend creating slots with simple assignment
instead:

slot = object()

class Foo():
    __metaclass__ = SlotsMetaclass
    foo = slot

class Bar():
    bar = slot

Then replace

"isinstance(v,slot)" with "v is slot"

in the metaclass.



> Here is the metaclass:
>
> class slot(object):
>     """Slot Decorator"""
>
>     def __init__(self, func):
>         pass
>
> class SlotMetaclass(type):
>     """Inheritable Slots Metaclass"""
>
>     def __new__(cls, name, bases, attrs):
>         # make a normal class, and get its attributes to decide which
> ones are slots
>         tmpcls = type.__new__(cls, name, bases, attrs)
>         slots = []
>         for k in dir(tmpcls):
>             v = getattr(tmpcls, k)
>             if isinstance(v, slot):
>                 slots.append(k)
>         # clean up
>         del tmpcls
>         for x in slots:
>             del attrs[x]
>         # create the real class with __slots__
>         attrs['__slots__'] = slots
>         return type.__new__(cls, name, bases, attrs)

You don't need to create a temporary class here; you should loop
through the base classes and inspect their slots.  Also, you don't
need to recreate slots that exist in base classes, so you could just
get all the new slots from the class dict.

You should consider corner cases if you think it should be standard.
For instance, what if a derived class defined the same slot as a a
base class--it'll create a new slot in yours but it shouldn't.  What
if you want to create a subclass that does have a dict?  Can't do it
in your version.  You need to consider stuff like that.


Carl Banks



More information about the Python-list mailing list