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.
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.