Title: tuple(a list subclass) does not iterate through the list
Type: behavior Stage: resolved
Components: Versions: Python 3.4, Python 2.7
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: rhettinger Nosy List: rhettinger, siming85, terry.reedy, xiang.zhang
Priority: normal Keywords:

Created on 2016-10-14 15:01 by siming85, last changed 2016-10-15 13:18 by berker.peksag. This issue is now closed.

File name Uploaded Description Edit terry.reedy, 2016-10-14 22:57 siming85, 2016-10-15 01:41
Messages (3)
msg278652 - (view) Author: Siming Yuan (siming85) * Date: 2016-10-14 15:01
if you subclass a list, and cast it to tuple, the casting does not iterate through the list.
(casing to list does)

for example, i needed a WeakList where the list only internally contains WeakReferences that gets deleted as soon as the object ref count goes to zero.. so:

import weakref

class WeakList(list):

    def __init__(self, items = ()):
        super(WeakList, self).__init__([weakref.ref(i, self.remove) for i in items])

    def __contains__(self, item):
        return super(WeakList, self).__contains__(weakref.ref(item))

    def __getitem__(self, index):
        if isinstance(index, slice):
            return [i() for i in super(WeakList, self).__getitem__(index)]
            return super(WeakList, self).__getitem__(index)()

    def __setitem__(self, index, item):
        if isinstance(index, slice):
            item = [weakref.ref(i, self.remove) for i in item]
            item = weakref.ref(item, self.remove)

        return super(WeakList, self).__setitem__(index, item)

    def __iter__(self):
        for i in list(super(WeakList, self).__iter__()):
            yield i()

    def remove(self, item):
        if isinstance(item, weakref.ReferenceType):
            super(WeakList, self).remove(item)
            super(WeakList, self).remove(weakref.ref(item))

    def append(self, item):
        return super(WeakList, self).append(weakref.ref(item, self.remove))

# write some test code:
class Dummy():
a = Dummy()
b = Dummy()

l = WeakList()

<__main__.Dummy instance at 0x7f29993f4ab8>

<__main__.Dummy instance at 0x7f29993f4b00>

[<weakref at 0x7f2999433e68; to 'instance' at 0x7f29993f4ab8>, <weakref at 0x7f2999433ec0; to 'instance' at 0x7f29993f4b00>]

print([i for i in l])
[<__main__.Dummy instance at 0x7f29993f4ab8>, <__main__.Dummy instance at 0x7f29993f4b00>]

[<__main__.Dummy instance at 0x7f29993f4ab8>, <__main__.Dummy instance at 0x7f29993f4b00>]

(<weakref at 0x7f2999433e68; to 'instance' at 0x7f29993f4ab8>, <weakref at 0x7f2999433ec0; to 'instance' at 0x7f29993f4b00>)

^ notice how you are getting weak references back instead of tuples.
msg278673 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2016-10-14 22:57
(Siming, when you post a mixture of code and output, please comment out output with # so the example can be run as is.)

I cannot reproduce the difference reported.  I added #s and ran the cut and pasted code (uploaded) on 2.7, 3.5, and 3.6 installed on Win 10.  For 3.6, 

Python 3.6.0b2 (default, Oct 10 2016, 21:15:32) [MSC v.1900 64 bit (AMD64)] on win32

For me, the tuple output is exactly the same as the list output, except for '()' versus '[]'.  In 3.5+, 'instance' is changed to 'object' for both list and tuple.  

(<__main__.Dummy object at 0x000001839C1F32E8>, <__main__.Dummy object at 0x000001839C384DA0>)

Siming, please cut and paste the interactive splash line, like the above, that tells us the binary and OS you used.
msg278681 - (view) Author: Siming Yuan (siming85) * Date: 2016-10-15 01:41
my apologies, was in a rush to get it posted. attached a better version of the file.

i can reproduce this in python 3.4.1 and python 2.7.8 (both 32 and 64 bit) on RHEL 6.6

however after verifying again - this doesn't seem to be an issue in 3.4.5 (did not verify earlier versions), so it is indeed already fixed. closing.

time to upgrade!
Date User Action Args
2016-10-15 13:18:25berker.peksagsetresolution: fixed -> out of date
stage: resolved
2016-10-15 01:41:52siming85setstatus: open -> closed
files: +
versions: + Python 3.4, - Python 3.5
messages: + msg278681

resolution: fixed
2016-10-14 22:58:18terry.reedysetversions: + Python 3.5, - Python 3.4
2016-10-14 22:57:58terry.reedysetfiles: +
nosy: + terry.reedy
messages: + msg278673

2016-10-14 18:08:02xiang.zhangsetnosy: + xiang.zhang
2016-10-14 15:02:39rhettingersetassignee: rhettinger
2016-10-14 15:02:24siming85setnosy: + rhettinger
2016-10-14 15:01:36siming85create