promoting [] by superclass?
Jim Newton
jimka at rdrop.com
Tue Jun 8 16:54:07 EDT 2004
i see, that does indeed help a lot. So from what you are saying,
it is impossible to have the class name work as both a factory
function and a casting function. I must decide whether i want
Pair( [] ) to build a linked list of its arguments, or simply
to do the class promotion, but it cannot be smart enough to
do both.
So the next best thing would be to have a cast funcion which
calls list().
So it would be great if Pair(1,2,3,4,5) would
return [1, [2, [3, [5, nil]]]] with all the bracketed
lists promoted to class Pair. Can that be done
with the __init__ function? currently i'm doing that
with a seperate function which takes any sequence as its argument.
Basically i'd like the Pair.__init__ in the case of Pair(1,2,3,4,5),
to set self[0]=1, and self[1] = Pair(2,3,4,5) in some iterative
way.
def seq2pair(seq):
new = Pair()
for index in xrange( len(seq), 0, -1):
new = new.cons(seq[index - 1])
return new
class Pair(list):
...
# x = (cons x list)
# ==> x = list.cons(x)
def cons(self, car):
new = Pair()
new.append(car)
new.append(self)
return new
Robert Brewer wrote:
> Jim Newton wrote:
>
>>this is interesting. I though that if you passed
>>an argument to your class factory function, it would call
>>the __init__ with that argument.
>>
>>class x1(list):
>> def __init__(y):
>> pass
>>
>>class x2(list):
>> pass
>>
>>what does x1([]) do and what does x2([]) do?
>
>
> x1([]) first calls x1.__new__, but since you're not overriding that, it
> moves up the class heirarchy to the next superclass, which is 'list',
> and calls list.__new__(cls, sequence). Notice that there are two
> arguments to this method. That method is written in such a way that the
> result is of type 'cls' (in your example, cls == x1). So when this
> method returns, we've got an object of type 'x1'.
>
> Then x1.__init__ gets called, passing it the new object and the
> 'sequence' arg. However, you've overridden list.__init__; moreover, it
> doesn't have the same number of arguments as __new__ did, so you get a
> TypeError saying that __init__ takes a different number of arguments. If
> you want to override __init__, it should be written:
>
>
>>>>class x1(list):
>
> ... def __init__(self, sequence):
> ... pass
> ...
>
>>>>x1([])
>
> []
>
>>>>type(x1([]))
>
> <class '__main__.x1'>
>
> Now, that only works if you wish to keep the same signature (arguments).
> If you want to provide another argument to the class instantiation, you
> need to override both __new__ and __init__ so that their argument lists
> "match":
>
>
>>>>class x1(list):
>
> ... def __new__(cls, sequence=[], maxlen=5):
> ... return list.__new__(cls, sequence)
> ... def __init__(self, sequence=[], maxlen=5):
> ... self.maxlen = maxlen
> ...
>
>>>>x1([])
>
> []
>
>>>>type(x1([]))
>
> <class '__main__.x1'>
>
>>>>x1([], 7)
>
> []
>
>>>>x1([], 7).maxlen
>
> 7
>
> x2 doesn't override anything, so the default list.* methods get called
> for all operations. Remember, though, that list.__new__ produces an
> object whose type is the subclass automatically, without overriding;
> therefore:
>
>
>>>>class x2(list): pass
>
> ...
>
>>>>type(x2([]))
>
> <class '__main__.x2'>
>
>
> Hope that helps!
>
> Robert Brewer
> MIS
> Amor Ministries
> fumanchu at amor.org
>
More information about the Python-list
mailing list