al********@yahoo.fr wrote:
I have what in my eyes seems a challenging problem.
Thanks to Peter Otten, i got the following code to work. It is a sort
of named tuple.
Don't trust code posted in a newsgroup -- it may sometimes be
quality-challenged :-)
Now my problem is the following. I want to write a function called
createDerivedTuple in order to create a class derived from the one
created with the function createTuple, taking the parent class as first
argument:
def createDerivedTuple(parentclass,*names):
....... code yet to be figured out ....
The usage should be as follows:
DerivedPoint=makeDerivedTuple(Point,'z')
p=DerivedPoint(4,7,9)
assert p.x==p[0]
assert p.y==p[1]
assert p.z==p[2]
assert DerivedPoint.x==0
assert DerivedPoint.y==1
assert DerivedPoint.z==2
I am still a newbie on metaclasses but i am convinced there are elegant
solutions to this challenging problem.
Hey, if you don't try to solve it yourself we'll end up with me learning
more than you...
I didn't find a way to extend the approach with a per-class metaclass to
support inheritance. I think you would have to subclass both class and
metaclass. So I had to start all over again:
class IndexProperty(object):
def __init__(self, index):
self.index = index
def __get__(self, inst, cls):
index = self.index
if inst is None:
return index
return inst[index]
class TupleType(type):
def __new__(mcl, name, bases, classdict):
names = classdict.get("_names")
if names is not None:
for base in bases:
base_names = getattr(base, "_names", None)
if base_names is not None:
offset = len(base_names)
break
else:
offset = 0
for i, n in enumerate(names):
classdict[n] = IndexProperty(offset + i)
if offset:
names[:0] = base_names
return type.__new__(mcl, name, bases, classdict)
class Tuple(tuple):
__metaclass__ = TupleType
def __new__(cls, values):
self = tuple.__new__(cls, values)
if len(self) != len(cls._names):
raise TypeError
return self
import unittest
class P2(Tuple):
_names = ["x", "y"]
class P3(P2):
_names = ["z"]
def yield_them(seq):
"""Helper to ensure the implementation cannot rely on len()."""
for item in seq:
yield item
class Test(unittest.TestCase):
def test_P2(self):
self.assertEquals(P2.x, 0)
self.assertEquals(P2.y, 1)
self.assertRaises(AttributeError, lambda: P2.z)
def test_P3(self):
self.assertEquals(P3.x, 0)
self.assertEquals(P3.y, 1)
self.assertEquals(P3.z, 2)
def test_P2_inst(self):
self.assertRaises(TypeError, P2, yield_them("A"))
self.assertRaises(TypeError, P2, yield_them("ABC"))
p = P2(yield_them("AB"))
self.assertEquals(p.x, "A")
self.assertEquals(p.y, "B")
self.assertRaises(AttributeError, lambda: p.z)
def test_P3_inst(self):
self.assertRaises(TypeError, P3, yield_them("A"))
self.assertRaises(TypeError, P3, yield_them("ABCD"))
p = P3(yield_them("ABC"))
self.assertEquals(p.x, "A")
self.assertEquals(p.y, "B")
self.assertEquals(p.z, "C")
self.assertRaises(AttributeError, lambda: p.t)
if __name__ == "__main__":
unittest.main()
I did not perform any tests other than the unittest given above.
Peter