A confusing object composition python code

Question:

Currently, I am on an online crash course on python and I encountered a confusing code.

As shown below, it is a code that is designed to find out the number of cotton polo shirts.

 class Clothing:
   stock={ 'name': [],'material' :[], 'amount':[]}
   def __init__(self,name):
     material = ""
     self.name = name
   def add_item(self, name, material, amount):
     Clothing.stock['name'].append(self.name)
     Clothing.stock['material'].append(self.material)
     Clothing.stock['amount'].append(amount)
   def Stock_by_Material(self, material):
     count=0
     n=0
     for item in Clothing.stock['material']:
       if item == material:
         count += Clothing.stock['amount'][n]
         n+=1
     return count

 class shirt(Clothing):
   material="Cotton"
 class pants(Clothing):
   material="Cotton"

 polo = shirt("Polo")
 sweatpants = pants("Sweatpants")
 polo.add_item(polo.name, polo.material, 4)
 sweatpants.add_item(sweatpants.name, sweatpants.material, 6)
 current_stock = polo.Stock_by_Material("Cotton")
 print(current_stock)

it is obvious that the number of cotton polo shirts is 4 and yet the code gives 10, the sum of the number of cotton polo and sweatpants, as the answer (which is considered a correct one actually).

My question is, shouldn’t the polo.Stock_by_Material method only iterates elements in the dictionary in the instance “polo” instead of both “polo” and “sweatpants”? I mean “polo” and “sweatpants” are not even in the same class so how come the polo.Stock_by_Material method would count the amount of both classes?

Please forgive me if I made some stupid mistakes here. I am only 1 week into python without any prior programming experience. Many thanks!

Asked By: CD-ROM

||

Answers:

You are aggregating by the material (Cotton). Both the shirt and sweatpants class has the material attribute set as Cotton. Hence there are 10 Cotton items, which is what you are displaying at the end.

If you want to aggregate by item, you could do as shown below.

class Clothing:
   stock={ 'name': [],'material' :[], 'amount':[]}
   def __init__(self,name):
     material = ""
     self.name = name
   def add_item(self, name, material, amount):
     Clothing.stock['name'].append(self.name)
     Clothing.stock['material'].append(self.material)
     Clothing.stock['amount'].append(amount)
   def Stock_by_Material(self, material):
     count=0
     n=0
     for item in Clothing.stock['material']:
       if item == material:
         count += Clothing.stock['amount'][n]
         n+=1
     return count
   def Stock_by_item(self, name):
     count=0
     n=0
     for rec in Clothing.stock['name']:
       if rec == name:
         count += Clothing.stock['amount'][n]
         n+=1
     return count

class shirt(Clothing):
   material="Cotton"

class pants(Clothing):
   material="Cotton"

polo = shirt("Polo")
other_polo_shirts = shirt("Polo")

sweatpants = pants("Sweatpants")
polo.add_item(polo.name, polo.material, 4)
other_polo_shirts.add_item(other_polo_shirts.name, other_polo_shirts.material, 16)

sweatpants.add_item(sweatpants.name, sweatpants.material, 6)
current_stock = polo.Stock_by_item("Polo")
print(current_stock)
Answered By: Sagi

If i got your question right,

stock is a static variable for the class Clothing. any children classes of this will share this variable.

Hence both polo and sweatpants share the same dictionary.

Hope that is helpful.

Answered By: Noorullah Farid

As @Sagi mention it returns all cotton stock as stock is shared between objects of Cloathing and its subclasses. Your confusion however is reasonable as this code breaks single responsibility principle, stock shouldn’t be part of Clothing class.

Answered By: Jakub GÄ…siewski

Sagi is correct. The Stock_by_Material function needs to also check ‘name’ to make sure it is ‘Polo’, only then adding it to the count. You’re not missing anything, the makers of the course just made an error.

Answered By: Brayden Peoples

In this conditional statement create problem in iteration so, try to comment it out. Sourly your program will run.

class Clothing:
  stock={ 'name': [],'material' :[], 'amount':[]}
  def __init__(self,name):
    material = ""
    self.name = name
  def add_item(self, name, material, amount):
    Clothing.stock['name'].append(self.name)
    Clothing.stock['material'].append(self.material)
    Clothing.stock['amount'].append(amount)
  def Stock_by_Material(self, material):
    count=0
    n=0
    for item in Clothing.stock['amount']:
      # if item == material:
        count += Clothing.stock['amount'][n]
        n+=1
    return count

class shirt(Clothing):
  material="Cotton"
class pants(Clothing):
  material="Cotton"
  
polo = shirt("Polo")
sweatpants = pants("Sweatpants")
polo.add_item(polo.name, polo.material, 4)
sweatpants.add_item(sweatpants.name, sweatpants.material, 6)
current_stock = polo.Stock_by_Material("Cotton")
print(current_stock)
Answered By: Nitya Nand
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.