__slots__

flori fgrimm at inneo.de
Fri Nov 7 17:36:39 CET 2003


i try to greate somthing like this

class ca(object): __slots__ = ("a",)
class cb(ca): __slots__ = ("a","b")
class cc(ca): __slots__ = ("a","c")
class cd(cb,cc): __slots__ = ("a","b","c","d")

but i didn't find a simple solution
so i'm using a metaclass that generate a __slots__-free and a
__slots__-version
the __slots__ -free is returned
the __new__ of the base class look for the sloted verion
the classes defines a (class)-attribute __object_slots__ with their
new attribute names.

killer? someone a good idea?

my soure (something not important i'm cutting away)

import sys
import types
import inspect
import weakref
#import 
#
class const(object):
    __slots__=()
    cs_classid = intern("_classid")
    cs__all_persitent_slots__ = intern("__all_persitent_slots__")
    cs__all_nonpersitent_slots__ =
intern("__all_nonpersitent_slots__")
    cs__all_slots__ = intern("__all_slots__")
    cs__cls_unsloted__ = intern("__cls_unsloted__")
    cs__nonpersitent_slots__ = intern("__nonpersitent_slots__")
    cs__object_slots__ = intern("__object_slots__")
    cs__object_slots_nomore__ = intern("__object_slots_nomore__")
    cs__slots__ = intern("__slots__")
    cs__slots_fixed__ = intern("__slots_fixed__")
    cs_lstobjProperty = intern("_lstobjProperty")
    cslstSlots = intern("lstSlots")
    cs_sloted_prefix = intern("_sloted_")
    cslstNonPersitentSlots = intern("lstNonPersitentSlots")
    #
#
class ClCustomBase(object):
    """ no really need for this but i like it
        may be i need for debugging, if..
    """
    pass
#
class ClMetaClass(ClCustomBase):
    #
    def __new__(cls, sName, tupBases, dctClassDefinition):
        """ calculates the class-attribute.
            calcs
                __all_slots__ := __object_slots__ + (for all
tupBases).__all_slots__
                __all_nonpersitent_slots__ := __nonpersitent_slots__ +
(for all tupBases).__all_nonpersitent_slots__
                __all_persitent_slots__ := __all_slots__ -
__all_nonpersitent_slots__
        """
        # init 
        objClsUnsloted=None
        dctDefinitionLocals = sys._getframe(1).f_locals
        # create a (hopefully) unique name
        # first i try to use the id(objClsUnsloted) but it's not known
before creation
        # - and i should know it before
        dctClassDefinition[const.cs_classid] = sName +
hex(id(tupBases) ^ id(sys._getframe(0)) ) ^
id(dctClassDefinition.get(const.cs__object_slots__, None))
        dctAddInfo = {
                const.cslstSlots: list(),
                const.cslstNonPersitentSlots: list(),
            }
        # prepare definition of unsloted
        cls.calculateSlots(sName, tupBases, dctClassDefinition,
dctAddInfo, dctDefinitionLocals)
        objClsUnsloted = type(sName, tupBases, dctClassDefinition)
        #
        # prepare definition of sloted
        dctClassDefinition[const.cs__slots__] =
tuple(dctAddInfo[const.cslstSlots])
        dctClassDefinition[const.cs__cls_unsloted__] = objClsUnsloted
        # definition of the sloted class
        objClsSloted = type(const.cs_sloted_prefix+sName,
(objClsUnsloted,), dctClassDefinition)
        objClsUnsloted.__cls_sloted__ = objClsSloted
        dctDefinitionLocals[const.cs_sloted_prefix+sName] =
objClsSloted
        # done
        dctDefinitionLocals = None # help gc
        return objClsUnsloted
    #
    def __init__(self, sName, tupBases, dctClassDefinition):
        super(ClMetaBase,self).__init__(sName, tupBases,
dctClassDefinition)
    #
    def calculateSlots(cls, sName, tupBases, dctClassDefinition,
dctAddInfo, dctDefinitionLocals):
        """ calculates all slot things needed fo the sloted version -
ah you geuess it
        """
        lstSlots=dctAddInfo[const.cslstSlots]
        tupClassSlots =
dctClassDefinition.get(const.cs__object_slots__, None)
        if isinstance(tupClassSlots, basestring):
            raise TypeError, "in class "+sName+":__object_slots__ is
defined as string (may be you forgotten a ,?)"
        if tupClassSlots is None:
            # or should we simply pass ? 
            raise TypeError, "The class "+sName+" (with ClBase as
superclass) must have a __object_slots__-attribute like
\n__object_slots__ = "+str(tuple(lstSlots))+".\n"+", but
-"+str(tupClassSlots)+"- found \n"
        else:
            lstSlots.extend( tupClassSlots )
        #
        lstNonPersitentSlots=dctAddInfo[const.cslstNonPersitentSlots]
        lstNonPersitentSlots.extend(
dctClassDefinition.get(const.cs__nonpersitent_slots__, ()) )
        #
        for objCls in tupBases:
            tupSubSlots = getattr(objCls, const.cs__all_slots__, None)
            if tupSubSlots is not None:
                lstSlots.extend(tupSubSlots)
            #
            tupSubSlots = getattr(objCls,
const.cs__nonpersitent_slots__, None)
            if tupSubSlots is not None:
                lstNonPersitentSlots.extend(tupSubSlots)
            #no more needed
            #lstBasesUnsloted.append(getattr(objCls,
cs__cls_unsloted__, objCls))
        #
        #no more needed
        #dctAddInfo["tupBasesUnsloted"] = tuple( lstBasesUnsloted )
        #add nonpersitent slots to the all slots
        #
        lstNonPersitentSlots.sort()
        for iIndex in xrange(len(lstNonPersitentSlots)-2, -1, -1):
            if lstNonPersitentSlots[iIndex] ==
lstNonPersitentSlots[iIndex+1]:
                del lstNonPersitentSlots[iIndex+1]
            #
        #
        tupObjectSlotsNoMore =
dctClassDefinition.get(const.cs__object_slots_nomore__, None)
        if tupObjectSlotsNoMore is not None:
            for sObjectSlotsNoMore in tupObjectSlotsNoMore:
                try:
                    lstNonPersitentSlots.remove(sObjectSlotsNoMore)
                except ValueError:
                    pass
                #
            #
        #
        lstSlots.extend(lstNonPersitentSlots)
        #sort slots and remove doubles
        lstSlots.sort()
        for iIndex in xrange(len(lstSlots)-2, -1, -1):
            s=intern(lstSlots[iIndex])
            if s == lstSlots[iIndex+1]:
                del lstSlots[iIndex+1]
            else:
                lstSlots[iIndex]=s
            #
        #
        if tupObjectSlotsNoMore is not None:
            for sObjectSlotsNoMore in tupObjectSlotsNoMore:
                try:
                    lstSlots.remove(sObjectSlotsNoMore)
                except ValueError:
                    pass
                #
            #
        #        
        # non persitent and persitent are disjunct ==> persitent :=
slots - non persitenten
        lstPersitentSlots=lstSlots[:]
        for sKey in lstNonPersitentSlots:
            lstPersitentSlots.remove(sKey)
        #
        # update class definition
        dctClassDefinition[const.cs__all_slots__]=tuple(lstSlots)
        dctClassDefinition[const.cs__all_nonpersitent_slots__]=tuple(lstNonPersitentSlots)
        dctClassDefinition[const.cs__all_persitent_slots__]=tuple(lstPersitentSlots)
        #
        # normally there isn't a __slots__ - definition, but if we
cannot trust it
        try:
            dctClassDefinition.remove(const.cs__slots__)
        except:
            pass
        dctDefinitionLocals = None # help gc
    #
    calculateSlots=classmethod(calculateSlots)
    #
#
class ClBase(ClCustomBase):
    """ base of all
    """
    #
    __metaclass__ = ClMetaClass
    __object_slots__ = ()
    #__object_slots__ = ("gna", "__weakref__", )
    #__weakref__ = 1
    #
    def __new__(cls, *lstArgs, **kwArgs):        
        self = super(ClBase,
cls).__new__(getattr(cls,"__cls_sloted__",cls))
        return self
        #now __init__ is called
    # / __new__
    def __init__(self, *lstArgs, **kwArgs):
        super(ClBase, self).__init__()
    #
#




More information about the Python-list mailing list