metaclass & __slots__

Jonathan Hogg jonathan at onegoodidea.com
Thu Jul 4 03:21:16 EDT 2002


On 3/7/2002 22:17, in article
c2595393.0207031317.7d9bb013 at posting.google.com, "Holden Caulfield"
<phoebe_1 at att.net> wrote:

> It looks like because the Metalcass statement is executed in the end
> of the class statement, hence the class methods seems to have a
> "early" binding to the __slots__ variable. Is this behaviour normal?

The __slots__ stuff works at allocation rather than initialisation (along
with lots of other magic). So you need to override __new__ instead of
__init__ in your metaclass.

I made the following changes to your code:

-----
class MX(type):
    def __new__(cls,name,bases,dict):
        props = {}
        slots = dict.get('__slots__', [])
        print slots
        for v in dict.keys():
            vs = v.startswith
            if vs("_get_") or vs("_set_"):
                props[v[5:]] = 1
        for v in props.keys():
            fget = dict.get("_get_%s" % v, None)
            fset = dict.get("_set_%s" % v, None)
            dict[v] = property(fget,fset)
        slots.append("_%s__%s" % (name,v))
        dict['__slots__'] = slots
        return super(MX, cls).__new__(cls,name,bases,dict)

class X(object):
    __metaclass__ = MX
    __slots__ = ['z']
    def __init__(self):
        self.x = 1
        self.z = 2
    def _get_x(self):
        return self.__x
    def _set_x(self,v):
        self.__x = v

def Test():
    y = X()
    y.x = 4
    print y.x

if __name__ == "__main__": Test()
-----

which gives me the desired result. Note that you do all your work on the
dict in __new__ as the class hasn't been created yet (the 'cls' in the
__new__ method is 'MX'), then you chain the type.__new__ to do the actual
class creation.

Jonathan




More information about the Python-list mailing list