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