Where do I need to include raisins?

Shouldn’t the method in subclass of the exercise be changed from “def init(self, potatoes, celery, onions):” into “def init(self, potatoes, celery, onions, raisins):” i mean what would the “self.raisins = 40” refer to, if the content of the method in subclass be the same as in the parent class?

1 Like

Good point. The example does not really make much sense either way, but including the raisins in the subclass init() method does work. This code also passes the exercise:

class SpecialPotatoSalad(PotatoSalad):
  def __init__(self,potatoes, celery, onions, raisins = 40):
    super().__init__(potatoes, celery, onions)
    self.raisins = raisins
9 Likes

True, but does the code work if you don’t include “raisins” in the constructor for the subclass? Instinctively, I find it weird to declare

self.raisins = 40

without including “raisins” in the constructor.

2 Likes

@byteninja93187, you’re right: it does not work:

class SpecialPotatoSalad(PotatoSalad):
  def __init__(self, potatoes, celery, onions, raisins = 40):
    super().__init__(potatoes, celery, onions)
    self.raisins = raisins
    
sps = SpecialPotatoSalad(3,4,5)
print(sps.raisins)

# Output:
40

Now, comment out the line self.raisins = raisins

class SpecialPotatoSalad(PotatoSalad):
  def __init__(self, potatoes, celery, onions, raisins = 40):
    super().__init__(potatoes, celery, onions)
    # self.raisins = raisins

sps = SpecialPotatoSalad(3,4,5)
print(sps.raisins)

# Output:
Traceback (most recent call last):
  File "script.py", line 13, in <module>
    print(sps.raisins)
AttributeError: 'SpecialPotatoSalad' object has no attribute 'raisins'
2 Likes

Thanks, but I (and I think the previous contributors as well) was actually wondering whether the below would work:

class SpecialPotatoSalad(PotatoSalad):
  def __init__(self, potatoes, celery, onions):
    super().__init__(potatoes, celery, onions)
    self.raisins = raisins

Would you be able to declare the instance variable “self.raisins” without including it as a parameter in the constructor?

To me, it seems impossible but I definitely passed the exercise this way.

1 Like

Not if you try to actually instantiate an object!

class SpecialPotatoSalad(PotatoSalad):
  def __init__(self, potatoes, celery, onions):
    super().__init__(potatoes, celery, onions)
    self.raisins = raisins
    
sps = SpecialPotatoSalad(3,4,5)
# print(sps.raisins)

# Output:
Traceback (most recent call last):
  File "script.py", line 12, in <module>
    sps = SpecialPotatoSalad(3,4,5)
  File "script.py", line 10, in __init__
    self.raisins = raisins
NameError: name 'raisins' is not defined
1 Like

Thanks, I’ll report it!

1 Like

… and it doesn’t pass:capture

If you put inself.raisins = 40, you are assigning a value to raisins, but self.raisins = raisins throws a name error.

1 Like

Suprisingly many examples in this course don’t… :frowning: the deeper we go the dumber it gets.
I mean - for real, potato salad?
My contribution:
potatoes += 1

7 Likes

Ok, as far as I understand it: you would instantiate your potato salad with variable amounts of potatos, celery and onions. However, you always put in one pack of raisins into it, so you give it a value which is the content of the pack (40).

eg:

special_potato_salad = SpecialPotatoSalad(300, 50, 150)

print(special_potato_salad.onions)
#prints: 150
print(special_potato_salad.raisins)
#prints: 40

super_special_potato_salad = SpecialPotatoSalad(300, 50, 500)

print(super_special_potato_salad.onions)
#prints: 500
print(super_special_potato_salad.raisins)
#prints: 40
2 Likes

Could someone explain why this code works, even though raisins does not appear at all in the constructor?

  def __init__(self, potatoes, celery, onions):
    self.potatoes = potatoes
    self.celery = celery
    self.onions = onions
    
class SpecialPotatoSalad(PotatoSalad):
  def __init__(self, potatoes, celery, onions):
    super().__init__(potatoes, celery, onions)
    self.raisins = 40

sps = SpecialPotatoSalad(3,4,5)
print(sps.raisins)

2 Likes

The __init__() method is the constructor. raisins isn’t a parameter of the function because we are always going to use 40 raisins. The amounts of the other 3 ingredients varies, and those values are passed as arguments when we instantiate a SpecialPotatoSalad object. If we wanted to vary the number of raisins as well we could change the constructor:

class PotatoSalad():
  def __init__(self, potatoes, celery, onions):
    self.potatoes = potatoes
    self.celery = celery
    self.onions = onions
    
class SpecialPotatoSalad(PotatoSalad):
  def __init__(self, potatoes, celery, onions, raisins): #include raisins as a parameter
    super().__init__(potatoes, celery, onions) #do not pass raisins to the parent constructor
    self.raisins = raisins #assign the value passed in to the self.raisins property

sps = SpecialPotatoSalad(3,4,5,63)
print(sps.raisins) #prints: 63
7 Likes

Okay, thank you.
I must confess, object orientation makes my head hurt.

5 Likes

Amen… i was making great progress on this course until hit this ‘Classes’ topic. It has got me seriously stumped. So badly that i’ve started dreading learning Python. I remember the earlier classes i used to LOVE coming back & learning more, but not anymore. I hope the next topic will rejuvenate my interest in Python.

All these classes examples can easily be done without… i mean we can just write functions and simple code to do what these classes seem to be doing in an overly-complicated manner. Why bother with classes at all?

I’m yet to see a real life example where making classes is actually useful. Otherwise simple code & functions get the job done easily every time.

3 Likes

I think classes show their true advantages in real big applications and it helps manage data in meaningful way .

1 Like

Is my understanding true ?
here :

class SpecialPotatoSalad(PotatoSalad):
  def __init__(self, potatoes, celery, onions, raisins): #include raisins as a parameter
    super().__init__(potatoes, celery, onions) #do not pass raisins to the parent constructor
    self.raisins = raisins #assign the value passed in to the self.raisins property

this line tells child class to have new init function === >

def __init__(self, potatoes, celery, onions, raisins): #include raisins as a parameter

but this line says do not overwrite parent init function and copy stuffs already is in it == >

super().__init__(potatoes, celery, onions) #do not pass raisins to the parent constructor

and this line is usual to have we declare construction variables :

self.raisins = raisins #assign the value passed in to the self.raisins property

simply it creates new init method and with super() it copy parent variables for us and save us from re writing all variables parent class had already and we want to include them but need an extra variable which is done by add . And what if we want exclude a variable from parent class in child class ?

1 Like

Thanks for the example midlindner.

I am experiencing the same thing. Exactly the same thing - I felt competent and even if it took me forever to figure out - I was actually figuring out the offline challenges and all of the tests etc. This topic is the first time I’ve had to use the show answer option - and I’ve used it several times. This Classes topic feels like it’s not being explained well and is being blown through with a LOT of technical terms that are not clicking.

in terms of where this would be useful - Classes would be extremely useful for building games… I would think. Consider building characters. You could certainly use classes and inheritance to make a basic character class, then inheritance to give different attributes to say a fighter or mage, healer etc. A better example may be using inheritance for leveling up? level 1 character has “spark” level 10 has the use of “spark”…but also “lightning ball.” Or for use with items like power up “objects”

anyway - the idea of classes makes sense to me. The syntax of it and the way these lessons are asking us to do things are just confusing.

6 Likes

Sorry for the late reply. I must have missed the notification when you replied.

From your description, it seems your understanding is correct.

There a several ways to accomplish this. One could argue that only attributes shared by all child classes should be included in the parent class, but if we insisted on including an attribute that we wanted to exclude from a child class we could make the parameter in the parent class constructor optional by assigning a default value such as None when it is not supplied. I added to my previous example to show a way to accomplish this:

class PotatoSalad():
    def __init__(self, potatoes, celery=None, onions=None):
        self.potatoes = potatoes
        if not celery == None: self.celery = celery
        if not onions == None: self.onions = onions
    
    def __str__(self):
        recipe = f'{self.__class__.__name__}\n--Ingredients--\n'
        for i, a in self.__dict__.items():
          recipe += f'{i}: {a}\n'
        return recipe
    
class SpecialPotatoSalad(PotatoSalad):
    def __init__(self, potatoes, celery, onions, raisins):
        super().__init__(potatoes, celery, onions)
        self.raisins = raisins
        
class EggyPotatoSalad(PotatoSalad):
    def __init__(self, potatoes, celery):
        super().__init__(potatoes, celery)
        self.eggs = potatoes * 2 #we'll have 2 eggs for every potato
        
sps = SpecialPotatoSalad(3,4,5,63)
print(sps)

#new recipe: eggy potato salad has no onions
eggy_ps = EggyPotatoSalad(6, 4)
print(eggy_ps)

#say you wanted regular potato salad without celery
#you could supply keyword arguments
ps = PotatoSalad(potatoes = 12, onions = 2)
print(ps)

Output:

SpecialPotatoSalad
–Ingredients–
potatoes: 3
celery: 4
onions: 5
raisins: 63

EggyPotatoSalad
–Ingredients–
potatoes: 6
celery: 4
eggs: 12

PotatoSalad
–Ingredients–
potatoes: 12
onions: 2

2 Likes

If you guys still confuse about Class, I recommend to watch these videos on youtube. He explains in an easier way.

1 Like

This is also a nice video explaining the benefit of using classes

1 Like