parameterized metaclass (or metametaclass)

A

Antoine Pitrou

Hi,

I've been looking at writing parameterized metaclasses and here are the
two solutions I've come to:
(my goal was to build a way to automatically add a hash function that
would take into account a selected list of object attributes)

1. all-in-one metametaclass:

class Autohash2(type):
"""
Metametaclass that instantiates into a metaclass creating
a hash function based on the attributes passed on instantiation.
"""
def __new__(cls, hash_attributes):
def class_new(cls, name, bases, d):
print "New class", name
l = hash_attributes
_hash = hash
_tuple = tuple
c = _hash(_tuple([_hash(k) for k in l]))
def object_hash(obj):
g = obj.__getattribute__
return _hash(_tuple([_hash(g(k)) for k in l]))
d['__hash__'] = object_hash
return super(Autohash2, cls).__new__(cls, name, bases, d)
name = '__private'
bases = (type,)
d = {'__new__': class_new}
print "New metaclass", name
return type.__new__(cls, name, bases, d)

2. with the metametaclass property slightly abstracted away:

class Metametaclass(type):
def __new__(cls, name, bases, dict_):
d = { '__new__': dict_['class_new'] }
def meta_new(cls, *args, **kargs):
print "New metaclass"
name = '__private'
bases = (type,)
return super(Metametaclass, cls).__new__(cls, name, bases, d)
dict_['__new__'] = meta_new
print "New metametaclass", name
return type.__new__(cls, name, bases, dict_)

class Autohash(type):
__metaclass__ = Metametaclass

def __init__(cls, hash_attributes):
cls.hash_attributes = hash_attributes

def class_new(cls, name, bases, d):
print "New class", name
l = cls.hash_attributes
_hash = hash
_tuple = tuple
c = _hash(_tuple([_hash(k) for k in l]))
def object_hash(obj):
g = obj.__getattribute__
return _hash(_tuple([_hash(g(k)) for k in l]))
d['__hash__'] = object_hash
return super(Autohash, cls).__new__(cls, name, bases, d)


Both of those metametaclasses can be used (successfully!) in the
following way:

class Address(object):
__metaclass__ = Autohash3(('host', 'port'))
# <snip rest of class definition>

a = Address()
a.host = 'localhost'
a.port = 5555
b = copy.copy(a)
hash(a) == hash(b)


I was wondering if there is some simpler way of building parameterized
metaclasses ?

Regards

Antoine.
 
M

michele.simionato

I was wondering if there is some simpler way of building
parameterized
metaclasses ?

Why not just a function returning metaclasses?

def metaFactory(*args):
dic = <something possibly depending on args>
return type("somemetaclass", (type,), dic)

Alternatively, a metaclass classmethod returning a metaclass, so that
you can use something like

__metaclass__ = MyMetaclass.with(*args) # classmethod returning a
metaclass

Michele Simionato
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,581
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top