I'm trying to overload UserList methods (add, append, extend) to get no duplicates. For some reason, I still get alpha twice. I even get an empty list if I just try to print the original_list Here's the code I wrote:
#!/usr/bin/env python
#coding: utf-8
from collections import UserList
class Ulist(UserList):
def __init__(self, info = []):
UserList.__init__(self)
self.info = info
def __add__(self, something_new):
for i in something_new:
if i in self:
print('%r This is already in the list.' % (i))
else:
return UserList.__add__(self, something_new)
def append(self, something_new):
if something_new in self:
print('%r This is already in the list.' % (i))
else:
return UserList.append(self, something_new)
def extend(self, something_new):
for i in something_new:
if i in self:
print('%r This is already in the list.' % (i))
else:
return UserList.extend(self, something_new)
# let's test how it works
original_list = Ulist(['alpha'])
original_list.__add__([444])
original_list.append('alpha')
original_list.append('I_dont_exist_yet')
original_list.append(0)
original_list.extend([98, 98, 234,'alpha','beta','I_am_totally_new',33])
print(original_list)
Disclaimer: I'm aware people have asked a similar question regarding UserList and method overloading. I analysed these questions but still couldn't figure out why my code doesn't work. Also, I'm new to Python.
Are you trying to do something like this?
from collections import UserList
class Ulist(UserList):
def __init__(self, info = []):
UserList.__init__(self)
self.info = info
def add_iterable(self, iterable):
for i in iterable:
if i in self:
print('%r This is already in the list.' % (i))
else:
UserList.append(self, i)
return self
def __add__(self, something_new):
if hasattr(something_new, '__iter__'):
return self.add_iterable(something_new)
else:
return UserList.append(self, something_new)
def append(self, something_new):
if something_new in self:
print('%r This is already in the list.' % (i))
else:
return UserList.append(self, something_new)
def extend(self, something_new):
return self.add_iterable(something_new)
Test output:
98 This is already in the list.
'alpha' This is already in the list.
[444, 'alpha', 'I_dont_exist_yet', 0, 98, 234, 'beta', 'I_am_totally_new', 33]
This is only tangentially an answer, but I'd strongly recommend trying to implement similar operations in terms of each other. For example, __add__ is really just construction followed by an extend operation. And extend is really just repeated appends. If performance is not absolutely critical (and when you're implementing your own UserList, you've already given up on performance, by and large), it's much easier to have one known good implementation and implement other operations in terms of that known good operation.
So, for example, __add__ can be implemented as:
def __add__(self, other):
ret = self.__class__(self) # Alt: self.copy()
ret.extend(other)
return ret
So now as long as your constructor and extend method are correct, __add__ is correct automatically.
Then you implement extend in terms of append:
def extend(self, other):
for x in other:
self.append(x)
and now, if append is correct, then so are extend and __add__. Now, all you need to do is get append correct (and you can test it in isolation until you're sure it's correct).
As it happens, your append is already correct (assuming print is a reasonable way of reporting errors, it usually isn't). So with this __add__ and extend, and a working initializer method, you'd have working code.
Your existing code would not actually behave correctly regardless though. Your initializer is wrong; you set self.info to the input iterable but self.info is never used by collections.UserList (it uses the data attribute). If you want to make a safe initializer, do something like:
def __init__(self, info=()): # Never use mutable default arguments
UserList.__init__(self)
self.extend(info) # Reuse known good code
Again, this reuses known good code; if extend works (which in turn depends on append), then this initializer is good. If you want it optimized for the copy scenario, you can save duplicate checking work by using class internals:
def __init__(self, info=()):
UserList.__init__(self)
if isinstance(info, Ulist):
# Already deduped, copy without duplicate checking
self.data[:] = info.data
else:
self.extend(info)
The main point of this answer is: Build up from pieces, and don't repeat yourself (mnemonic: DRY). Don't try to implement each method from scratch when they're all variations on one another. Identify a single "common denominator" functionality, and build on top of that, so any given method either does a single simple thing, or is implemented in terms of another method in a way that minimizes custom code.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With