Mumo Mwendwa
Mumo Mwendwa

Reputation: 11

How do I call a classmethod inside the class in python?

When I call the classmethod within the init , where I initialize an object, the classmethod count_genre is called each time, incrementing values that were there before. I'd only like to call the method once.

class Furniture:

    materials = []
    material_count = {}

    def __init__(self, name, material):
        self.name = name
        self.material = material
        Furniture.materials.append(self.material)
        Furniture.count_material()

    @classmethod
    def count_material(cls):
        for material in cls.materials:
            cls.material_count[material] = cls.material_count.get(material, 0) + 1

Furniture("Chair", "Wood")
Furniture("Cushion", "Cotton")
Furniture("Table", "Glass")

print(Furniture.material_count)

This is what I get on my terminal: {'Chair': 3, 'Cushion': 2, 'Table': 1}

This is what I want to get: {'Chair': 1, 'Cushion': 1, 'Table': 1}

Upvotes: 0

Views: 68

Answers (3)

Laito
Laito

Reputation: 17

here it is following the logic of your question plus with your last question to my answer:

class Furniture:

    materials = set()
    material_count = {}

    def __init__(self, name: str, material: str):
        self.name = name
        self.material = material
        Furniture.materials.add(self.material)
        Furniture.count_material(self.material)

    @classmethod
    def count_material(cls, material):
        if material in cls.material_count:
            cls.material_count[material] += 1
        else:
            cls.material_count[material] = 1


Furniture("Chair", "Wood")
Furniture("Cushion", "Cotton")
Furniture("Table", "Glass")
Furniture("Cushion", "Cotton")

print(Furniture.material_count)  # {'Wood': 1, 'Cotton': 2, 'Glass': 1}

Upvotes: 0

Laito
Laito

Reputation: 17

The problem is that the material is added to the BOM every time a new piece of furniture is created and all the materials in the BOM are counted. This means that if you create several pieces of furniture with the same material, that material will be counted multiple times.

A simple solution would be to use an assembly instead of a list for the materials, which will automatically eliminate any duplicates. You can then convert the assembly to a list before counting the materials.

Here is the logic to solve it:

  • Define the Furniture class with two class attributes: materials and material_count. materials is an array that will store the unique materials used in the furniture, and material_count is a dictionary that will store the count of each material.

  • Define the init method that is executed when a new Furniture object is created. This method adds the material of the new object to the material set and then calls the count_material method.

  • Defines the count_material class method that updates the material_count dictionary to contain the count of each material in the materials set. Since materials is an assembly, each material will only be counted once, no matter how many Furniture objects use it.

  • Create some furniture and print the material_count dictionary to verify that each material has been counted only once. Code:

class Furniture:

    materials = set()
    material_count = {}

    def __init__(self, name: str, material: str):
        self.name = name
        self.material = material
        Furniture.materials.add(self.material)
        Furniture.count_material()

    @classmethod
    def count_material(cls):
        cls.material_count = {material: 1 for material in cls.materials}


Furniture("Chair", "Wood")
Furniture("Cushion", "Cotton")
Furniture("Table", "Glass")

print(Furniture.material_count)  # {'Cotton': 1, 'Wood': 1, 'Glass': 1}

Upvotes: 0

chepner
chepner

Reputation: 531055

Use Furniture to model a piece of furniture. Use a separate class to model information about a particular set of pieces of furniture.

import dataclass
import collections


@dataclasses.dataclass
class Furniture:
    name: str
    material: str



class FurnitureCollection:
     def __init__(self):
         self.material_count = collections.Counter()
         self.pieces = []

     def add(self, f: Furniture):
         self.pieces.append(f)
         self.material_count[f.material] += 1

     @property
     def materials(self):
         return list(self.material_count)


fc = FurnitureCollection()

fc.add(Furniture("Char", "Wood"))
fc.add(Furniture("Cushion", "Cotton"))
fc.add(Furniture("Table", "Glass"))


assert fc.material_count["Wood"] == 1
assert all(x in fc.materials for x in ["Wood", "Cotton", "Glass"])

Upvotes: 1

Related Questions