1

I want to remove duplicates in the list, but append elements in the list when there are no duplicates in the existing data but only in the extend() method, not in the append() method (because I will treat an added list in the append() method as one distinctive datum).

from collections import UserList

class Ulist(UserList):
    def __init__(self, list_=[]):
         UserList.__init__(self)
         self.list_=list_

    def __add__(self, another):
        for i in another:
            if i in self:
                raise ValueError
                print("Duplicated Data!")
            else:
                return UserList.__add__(self, another)

    def append(self, another):
        if another in self:
            raise ValueError
            print("Duplicated Data!")
        else:
            return UserList.append(self, another)

    def extend(self, another):
        for x in another:
            if x in self:
                print("Duplicated Data! Erase the Duplicated Data")
                listList=UserList.extend(self, another)
                listList=list(set(listList))
                return listList
                       
            else:
                return UserList.extend(self, another)

And this is the error message when I work with the list having an element duplicated with the existing list. I don't understand how TypeError: 'NoneType' object is not iterable applies. How do I correct the extend() method?

>>> l=Ulist()
>>> l.__add__([98])
[]
>>> l.append('kim')
>>> l.extend(['lee', 'park', 'choi'])
>>> l.append(['kim', 'jeong', 'kang'])
>>> l.extend(['lee', 'kim', 'joo'])
Duplicated Data! Erase the Duplicated Data
Traceback (most recent call last):
  File "<pyshell#110>", line 1, in <module>
    l.extend(['lee', 'kim', 'joo'])
  File "C:\Users\소현\AppData\Local\Programs\Python\Python38-32\User_list.py", line 28, in extend
    listList=list(set(listList))
TypeError: 'NoneType' object is not iterable
martineau
  • 119,623
  • 25
  • 170
  • 301
  • There is no point having a `print` statement immediately *after* `raise` - it will not be reached. – alani Aug 23 '20 at 14:40
  • 1
    Does this answer your question? [Removing duplicates in lists](https://stackoverflow.com/questions/7961363/removing-duplicates-in-lists) – Tsubasa Aug 23 '20 at 14:42
  • Also I'm not sure what `self.list_` is for, because you never use it. But it is not advisable to have a mutable object as a function default - if it is needed at all, then have it default to `None` and conditionally set it to `[]` within the body of `__init__`. – alani Aug 23 '20 at 14:44
  • Another issue you might have is that you default `list_` to `[]`. See this link for more info: https://docs.python-guide.org/writing/gotchas/#what-you-wrote – Paul H Aug 23 '20 at 15:32

5 Answers5

4

The problem here is that UserList.extend returns nothing (None). So in your code

                listList=UserList.extend(self, another)
                listList=list(set(listList))

listList on the first line is None. Then when you pass it to set, you get this error (the same as set(None))

Jan Stránský
  • 1,671
  • 1
  • 11
  • 15
1

Various issues with the code:

  • self.list_ is never used (and the base class does not use it either), so just remove it. Having removed it, there is no further purpose for your __init__, so remove that also. (If you did use it, then using a mutable argument as function default would also be a problem.)

  • UserList.append and UserList.extend both return None so there is no point in explicitly returning this value in your overridden versions (it will default to returning None on reaching end of the function).

  • You have statements after raise statements, which cannot be reached. Get rid of them, and you can incorporate the messages into the exception message.

  • In your extend, you are trying to iterate over the None returned from UserList.extend, and even if the item is not already found, you have a problem that you are doing the extend inside a loop over items so you can end up with the whole another list added multiple times.

  • It would also be a good idea to use super so that instead of Userlist.append(self, another) you use super().append(another). This would make it easier later to change which base class you inherit from.

Here is a revised version:

from collections import UserList

class Ulist(UserList):

    def __add__(self, another):
        for i in another:
            if i in self:
                raise ValueError("Duplicated Data!")
            else:
                return super().__add__(another)

    def append(self, another):
        if another in self:
            raise ValueError("Duplicated Data!")
        else:
            super().append(another)

    def extend(self, another):
        for x in another:
            if x in self:
                print("Duplicated Data! Erase the Duplicated Data")
            else:
                super().append(x)

Or you could also change extend to utilise the append method shown here:

    def extend(self, another):
        for x in another:
            try:
                self.append(x)
            except ValueError as exc:
                print(exc)
alani
  • 12,573
  • 2
  • 13
  • 23
  • Concerning the second point, I would say that one significant reason of subclassing is to change this behavior (to enable chaining for example) – Jan Stránský Aug 23 '20 at 16:58
  • @JanStránský Thanks, and fair enough if it actually did change this behaviour, but explicitly propagating the `None` that is returned seemed not really worth it, compared to being able to simplify the code a bit. I've changed the wording slightly so as to reflect better what I meant by it. – alani Aug 23 '20 at 17:15
0

Sounds like you're looking for set().

items = (
    "kim",
    "lee",
    "park",
    "choi",
    "kim",
    "jeong",
    "kang",
    "lee",
    "kim",
    "joo"
)
uniques = set()
for item in items:
    uniques.add(item)

This will only keep the unique items you add to the set.

Results:

{'choi', 'jeong', 'joo', 'kang', 'kim', 'lee', 'park'}

monkut
  • 42,176
  • 24
  • 124
  • 155
  • 1
    couple of things. 1) `uniques = set(items)` will let you skip the loop 2) the OP is already using `set`. the issue was the fact that the `List.extend` method mutates the original instead of returning a copy. – Paul H Aug 23 '20 at 14:46
  • Yes, the loop is done to show that items can be added in a similar way to `.append()`. This is an alternative solution, suggesting that this may resolve what the OP is trying to achieve in building a _list_ of items without duplicates. – monkut Aug 23 '20 at 22:51
0

the problematic line is this one:

                listList=UserList.extend(self, another)

here it seems to me that maybe the Userlist object is not initiated properly, and thus is None type. it is hard to tell what to do because we don't have the UserList init() method, but I think you might heave meant to do somthing such as:

def extend(self, another):
        for x in another:
            if x in self:
                print("Duplicated Data! Erase the Duplicated Data")
                listList=UserList(   ----- put args here ----     ).extend(self, another)
                listList=list(set(listList))
                return listList
Nadavo
  • 250
  • 2
  • 9
-1

After adding all the elements you want then use the following

x = list(set(x))

This will remove all the duplicates.