Bonus Challenge Discussion

Hi, I just finished the section on polymorphism, and here is what I came up with in order to make the SortedList to be sorted at initialization (spoilers, if you want to solve this bonus yourself, don’t look):

Code
class SortedList(list):
  def __init__(self, values):
    super().__init__(self)
    self.values = values
    self.values.sort()
  
  def append(self, value):
    super().append(value)
    self.sort()

  def __repr__(self):
    return str(self.values)

a = SortedList([3, 45, 1234, 21])

print(a)

And it works, but it seems that it forces me to keep the values outside of the parent class, that is, it seems I can’t make the super().__init__() function initialize the values I receive for me, I tried passing them directly to it, but it said that it only accepts one argument: self.

And this of course then forces me to overwrite __repr__(), because otherwise when I try to print my SortedList it prints an empty list (since the values are not accessible from the parent class).

So I would just like to know if there’s something I’m doing wrong/not optimized or if it’s how it’s supposed to work? In a way it would also make sense to work like that, because otherwise I don’t know how you would access the values in the subclass (maybe from a return from super() ?)

Thanks to anyone who takes the time to answer me.

3 Likes

H, @arjofocolovi. This my personal opinion and I’m no professional expert. I think your code does not exactly correspond to what the exercise asks for, which is that SortedList should be a child class implementation of List. This means that the sorted list is the class object itself. But in your case, the sorted list is the not the class object itself, but rather an instance variable defined inside the class, of type list and named values.

Anyway, here is my code. Hope it is what the exercise requires and hope it helps you.

My Code
class SortedList(list):
  
  def __init__(self, lst):
    super().__init__(lst)
    self.sort()
  
  def append(self, value):
    super().append(value)
    self.sort()
 

new_list = SortedList([4, 1, 5])
print(new_list)
new_list.append(0)
print(new_list)

5 Likes

Indeed, I discovered that later on during the last project, my mistake was to try to pass self when calling super() on __init__, which you shouldn’t do, otherwise you run out of arguments (and you don’t even give the proper arguments anyway). But thanks for your answer, I forgot to update this thread.

1 Like

Hello guys !
I’m new to programming and im struggling with classes right now. I’m trying to solve another task from this topic. To be exact:

" What other Python builtins have functionality “missing”? Could you write a new dictionary that uses a fallback value when it tries to retrieve an item and can’t?"

I tried to solved it by myself but it’s too hard for me :frowning: Here’s my code(it’s not working):

class SuperDict(dict):
  fallback_value = "There is no such a key"
  def __init__(self, dic):
    super().__init__(dic)
    self.dic = dic
  def __getitem__(self, key):
    super().__getitem__(key)
    try:
      self.dic[key]
    except KeyError:
      return print(fallback_value)


d = SuperDict({"k": 10, "b": 5})

print(d["c"])

Could someone take a look at this and try to explain to me what’s my mistakes are ? Thanks for help in advance.
PS I’m not english speaking person, so sorry for my english.

Regards,
Daniel.

1 Like

I need help with that one too. I’m not entirely sure what they mean by a “new dictionary that uses a fallback value”. Doesn’t every dictionary have the .get() method by default? What are they expecting us to write?

2 Likes

I have tried modifying your code a bit to make it work.

class SuperDict(dict):
  fallback_value = "There is no such a key"
  def __init__(self, dic):
    super().__init__(dic)
    self.dic = dic
  def get(self, key):
    super().get(key)
    try:
      return self.dic[key]
    except KeyError:
      return self.fallback_value


d = SuperDict({"k": 10, "b": 5})

print(d.get("c"))

I think the main issue is dunder method are specific for certain operators and may not be applicable to .get() build in method of the list class. I’ve edited getitem to be a regular method and it appears to work for tests I’ve conducted. Though I suspect the extra exercise actual instruction may be to modify the .get() method of the list class to return a fallback value instead of creating a new method for it.

I am new to programming and am now trying to understand this exercise myself.

Your reply really helped, but I could not understand a couple of things:

  • why overriding init at all,
  • why calling super().get(key) when it is not used.

I understand that it is probably because you are modifying the code which does have those elements already, but still, I wanted to see if I can simplify the code and still have the functionality:

class SuperDict(dict):
  fallback_value = "No such key"
  def get(self, key):
    try:
      return self[key]
    except KeyError:
      return self.fallback_value

aaa = SuperDict({1: "a", 2: "b"})
print(aaa.get(1))
print(aaa.get(6))

That seemed to work. Then i tried to change the code in order to override getitem as well:

class SuperDict(dict):
  fallback_value = "No such key"
  def __getitem__(self, key):
    try:
      return super().__getitem__(key)
    except KeyError:
      return self.fallback_value

aaa = SuperDict({1: "a", 2: "b"})
print(aaa[4])
print(aaa[1])
2 Likes

Hi Daniel,
For the same exercise i code this:

class FallbackDict(dict):
  fallback="Wrong key"
  def init(self,dic):
    super().__init__(dic)
    
  def __getitem__(self, key):
    try:
      return super().__getitem__(key)
    except KeyError:
      return print(self.fallback)

I think the problem that you are calling with [key] the method you want to change. The solution is super() calls the father’s method so you don’t have to add other stuff.
I hope you find it usefull.

  • When a SortedList gets initialized with unsorted values (say if you call SortedList([4, 1, 5]) ) those values don’t get sorted! How would you change SortedList so that the list is sorted right after the object gets created?
class SortedList(list):
  def __init__(self):
    self.sort()
  
  def append(self, value):
    super().append(value)
    self.sort()
    
print(SortedList([4, 1, 5]))

I get an error of init takes 1 positional argument but 2 were given. What’s wrong with my code when trying to solve the above question?

Sorry I don’t have a definitive answer for your question. The workaround I came up with (until such time as there is a reasonable answer) was to instantiate an empty list, and then append to it.

>>> class SortedList(list):
	def append(self, value):
		super().append(value)
		self.sort()

		
>>> x = SortedList()
>>> x.append(7)
>>> x.append(4)
>>> x.append(6)
>>> x.append(1)
>>> x
[1, 4, 6, 7]
>>> 

Another way would be to sort the list when passing it in.

>>> x = SortedList(sorted([7, 4, 6, 1]))
>>> x
[1, 4, 6, 7]
>>> x.append(-7)
>>> x
[-7, 1, 4, 6, 7]
>>> 

In either case the class has no initialization. Rather eager to see how this one is actually solved without using __init__().

Why is it desirable not to have an __init__() method?

Only to see if it can be done.

Unlike in some languages, __init__ is not a constructor, as such since the object already exists, AND has a value, just not named.

>>> class SortedList(list):
	def extend(self, value):
		super().extend(value)
		self.sort()
	def append(self, value):
		super().append(value)
		self.sort()

		
>>> x = SortedList()
>>> x.extend([7, 4, 6, 1, -7])
>>> x
[-7, 1, 4, 6, 7]
>>> 

Wrap it in a function???

def SortedList(value):
    
    class SortedList(list):          
      def append(self, value):
        super().append(value)
        super().sort()
      def extend(self, value):
        super().extend(value)
        self.sort()
        
    value.sort()
    new_lst = SortedList(value)
    return new_lst

my_list = [4,1,5]

lst = SortedList(my_list)
print(lst)

lst.append(-25)
print(lst)

lst.append(3)
print(lst)

lst.extend([8,4,2,-1])
print(lst)

# Output:
[1, 4, 5]
[-25, 1, 4, 5]
[-25, 1, 3, 4, 5]
[-25, -1, 1, 2, 3, 4, 4, 5, 8]

Not pretty, but …

1 Like

A rather novel approach. I fear we may both be caught out for our naivete.

We may need to rustle up a curriculum advisor to lift the fog. @alyssavigil can you please scare one up to weigh in on this topic?

Thanks. Perhaps best to use a conventional initializer?

Sorry, I don’t have an answer as to what is best. There is a lesson here that we do not want to miss out on.

I don’t think ‘SuperDict’ needs a constructor. The structure of ‘SuperDict’ is essentially the same as the Python canonical class ‘dict’. I think you just need to override the Python get() method.

This code seems to work:

image

Hello, I was reading Python doc and found something. You can use missing method in your customized dictionary and return whatever value you want in that method. NOTE that built-in dict class doesn’t have this missing method; so, don’t use super here Python will give you error.

class MyDict(dict):
  def __missing__(self, key):
    return 'Key not present'