Defining metaclass instance methods inside of the metaclass factory instead of the metaclass itself - flawed design? I'm wondering if this is good design, or if the definition of the __init__, __call__, and __repr__ methods should be inside of mesh_class_meta itself instead of inside of the factory, mesh_class. 

If it is better to for them to be defined inside of the metaclass definition, please explain specifically why? Or is there another even better way that I haven't thought of? 

debugprint = print

##Metaclass for mesh data subclasses
##Receives a list of valid fields in a string (similar to namedtuple)
##Adds those fields to __slots__
class mesh_class_meta(type):
    def __new__(meta, name, bases, fields):
        if isinstance(fields, str): fields = fields.replace(',',' ').split()
        fields = tuple(fields)
        debugprint('\n-------------------------')
        debugprint('Allocating memory for new mesh_class', name)
        debugprint(meta)
        debugprint(bases)
        debugprint(fields)
        debugprint('\n')
        dctn = {}
        dctn['__slots__'] = list(fields)
        return super(mesh_class_meta, meta).__new__(meta, name, bases, dctn)

    def __init__(klass, name, bases, fields):
        debugprint('\n-------------------------')
        debugprint('Initializing class', name)
        debugprint(klass)
        debugprint(bases)
        debugprint(fields)
        debugprint('\n')
        super(mesh_class_meta, klass).__init__(name, bases, {})

##mesh_class_meta factory
##__init__, __call__, and __repr__ for the subclasses are defined here
##__call__ allows the values of slot fields to be changed by calling the class
##with a valid dictionary argument 
def mesh_class(name, fields):
    new_class = mesh_class_meta(name, (object,), fields)
    def new_class__init__(self, *args, **kwargs):
        for slot, arg in enumerate(args):
            setattr(self, str(self.__slots__[slot]), arg)
        for k,v in kwargs.items():
            setattr(self, k, v)
        debugprint('\n-------------------------')
        debugprint('New', name, 'object created using', tuple(({attr: getattr(self, attr)} for attr in self.__slots__)))
        debugprint('\n')
        super(new_class, self).__init__() #Not sure if this is correct; seems to work
    new_class.__init__ = new_class__init__
    def new_class__call__(self, **kwargs):
        for k,v in kwargs.items():
            setattr(self, k, v)
        debugprint('\n-------------------------')
        debugprint('Fields in', name, 'object edited:', tuple(({k: v} for k,v in kwargs.items())))
        debugprint('\n')
    new_class.__call__ = new_class__call__
    def new_class__repr__(self):
        return str(name) + str({attr: getattr(self, attr) for attr in self.__slots__})
    new_class.__repr__ = new_class__repr__
    return new_class

##mesh classes created
Point = mesh_class('Point', 'x y')
Elpoints = mesh_class('Elpoints','i j k l')
Boundpoint = mesh_class('Boundpoint','b')

##Testing procedures##

##Create some instances
Points = [Point(p,p) for p in range(0,4,1)]
e1 = Elpoints(*tuple(p for p in Points))
b1 = Boundpoint(Points[2])

##Do some tests
assert Points[3].x == 3
Points[3](x = 4)
assert e1.l.x == 4
e1.j(y = 5)
assert Points[1].y == 5
e1.k(x=7)
assert b1.b.x == 7
assert Points[2].x == 7
e1(i = Points[3])
b1(b = Points[3])
Points[3](x=-1,y=-1)
assert e1.i.x, e1.i.y == (-1 , -1)
assert b1.b.x, b1.b.y == (-1 , -1)
It would seem to me that a simpler way (without a metaclass) to do more or less the same would be


Define a base class SlottedClass with empty __slots__.
Define  __init__, __call__, __repr__ etc. as normal instance methods in SlottedClass.
The class factory only needs to set __slots__ on the subclass it creates:

def mesh_class(name, fields):
    if isinstance(fields, str): 
        fields = fields.replace(',',' ').split()
    ##Test for repeated fields
    if len(set(fields)) &lt; len(fields): 
        raise Exception
    ##Test for fields beginning with underscore
    for field in fields:
        if field[0] == '_': 
            raise Exception
    new_class = type(name, (SlottedClass,), {'__slots__': fields})
    return new_class



Note by the way that list.sort() sorts in place and always returns None, so the code below does not do what it says. I've fixed it the code above.

    ##Test for repeated fields
    if list(set(fields)).sort() != list(fields).sort(): raise Exception