Changes to UserList.py

Jakob Schiotz schiotz1 at yahoo.com
Wed Jan 5 13:33:09 EST 2000


Dear Python Gurus,

Apparently, classes derived from UserList can be initialized with real
lists and with instances themselves derived from UserList but not with
other list-like objects (i.e. objects defining the methods you would
expect of a list).

Example:

>>> from UserList import UserList
>>> class test(UserList):
...     pass
...
>>> test(range(5))
[0, 1, 2, 3, 4]
>>> test(xrange(5))
Traceback (innermost last):
  File "<stdin>", line 1, in ?
  File "/usr/lib/python1.5/UserList.py", line 10, in __init__
    self.data[:] = list.data[:]
AttributeError: data


The problem is the constructor in UserList:

class UserList:
    def __init__(self, list=None):
        self.data = []
        if list is not None:
            if type(list) == type(self.data):
                self.data[:] = list
            else:
                self.data[:] = list.data[:]

It assumes that if list is not a real list then it must be a UserList.
In __setslice__ it is a little more clever:

    def __setslice__(self, i, j, other):
        i = max(i, 0); j = max(j, 0)
        if isinstance(other, UserList):
            self.data[i:j] = other.data
        elif isinstance(other, type(self.data)):
            self.data[i:j] = other
        else:
            self.data[i:j] = list(other)

should the same be done in __init__?  Should UserList.py be modified? 
However, this is not the ultimate solution...

We have a number of closely related list-like objects.  Some are
defined using UserList, others from scratch.  We need to be able to
"cast" lists of one type to another, and the convenient way to do that
is to initialize one object with another.  However, it does not work
because __init__ assumes that the argument to __init__ is a UserList
since it is not a list.  The trick of using list() will not work in
this case, as list() will not work on any list-like object
(list(xrange(5)) fails, for example).

This modified constructor works, but it would not do to modify UserList
in this way, as you no longer get the expected copying of the list

    def __init__(self, list=None):
        self.data = []
        if list is not None:
            if type(list) == type(self.data):
                self.data[:] = list
            else:
                self.data = list

Another possibility is to give all out objects a data attribute, it
should then be a wrapper object with a __getslice__ method returning a
real list.


I feel that the optimal solution would be a change in UserList.py, but
I cannot figure out how the optimal solution should be.  Perhaps
UserList.__init() should be changed to be similar to __cmp__, and then
the build-in function list() should be extended to work on any object
having a __getitem__ method.  The latter change should probably be done
anyway in a later version of Python.


Best regards,

Jakob Schiotz



=====
Jakob Schiotz, CAMP and Department of Physics, Tech. Univ. of Denmark,
DK-2800 Lyngby, Denmark.  http://www.fysik.dtu.dk/~schiotz/
This email address is used for newsgroups and mailing lists
(spam protection).  Official email: schiotz @ fysik . dtu . dk
When spammed too much, I'll move on to schiotz2 at yahoo.com
__________________________________________________
Do You Yahoo!?
Talk to your friends online with Yahoo! Messenger.
http://messenger.yahoo.com




More information about the Python-list mailing list