Can't call static method inside class

Question:

I am trying to call a static method inside a class to populate the class variable.

import sys
import os
from HelpingData import *

class Inventory(object):
    shipping_cost = 400.0   
    total_stock = calculate_total_stock.__func__()
    
    def __init__(self, attributes={}):
        self.inventory = {}
        if attributes is None:
             self.inventory = {}
        else:    
             for key in attributes:
                self.inventory[key] = attributes[key]  


    def getValue(self,attribute):
        return self.inventory[attribute]  
    

    def setValue(self,attribute,value):
        self.inventory[attribute]=value 
     
    @staticmethod        
    def calculate_total_stock():
       total_stock = dict((item, 0) for item in product_names)
       for nation in product_stock:
           for item in nation:
              total_stock[item] += nation[item]
       return total_stock   

And this is the error I am getting:

   total_stock = calculate_total_stock.__func__() 
 NameError: name'calculate_total_stock' is not defined

What am I missing here?

Asked By: Himanshu97

||

Answers:

The code at the top level of the Inventory definition (i.e. class attributes and method definitions) runs before the name Inventory exists, so you can’t call its own methods within the definition. As you have a @staticmethod, which doesn’t require any class or instance argument, why not move it outside?

def calculate_total_stock(product_names, product_stock):
    total_stock = dict((item, 0) for item in product_names)
    for nation in product_stock:
        for item in nation:
           total_stock[item] += nation[item]
    return total_stock


class Inventory(object):

    SHIPPING_COST = 400.0   
    TOTAL_STOCK = calculate_total_stock(product_names, product_stock)

    def __init__(self, attributes=None):
        self.inventory = {}
        if attributes is not None:
            for key in attributes:
                self.inventory[key] = attributes[key]  

    def get_value(self, attribute):
        return self.inventory[attribute]  

    def set_value(self, attribute, value):
        self.inventory[attribute] = value 

Note that I have done some tidying up, particularly in terms of style and making the explicit arguments to calculate_total_stock.

Answered By: jonrsharpe

You really don’t need any workaround here, just give the calling method an additional level of direction.

In the example below you can call the PrintThis() method both internal and external to its defining class.

External:

Call as you normally would

  • MyClass.PrintThis(’42’)

Internal:

You must add self or the containing class

  • MyClass.PrintThis(’42’)
  • self.PrintThis(’42’)

To produce the error:

class MyClass:

    def __init__(self):
        self.MyValue = 0

    def IncrementValue(self):
        self.MyValue += 1
    
        PrintThis(f'From MyClass {self.MyValue}')

    @staticmethod
    def PrintThis(arg):
        print(f'My Value: {arg}')

    

The Fix:

class MyClass:

    def __init__(self):
        self.MyValue = 0

    def IncrementValue(self):
        self.MyValue += 1
        self.PrintThis(f'From MyClass {self.MyValue}')

    @staticmethod
    def PrintThis(arg):
        print(f'My Value: {arg}')

Run It

    class Run:
        def __init__(self):
        
            mc = MyClass()

            MyClass.PrintThis('From Outside')

            mc.IncrementValue()
            mc.IncrementValue()



My Value: From Outside
My Value: From MyClass 1
My Value: From MyClass 2

Why?

I’m not sure 🙂

The only thing I noticed is that the static method (PrintThis) is a function, while the non-static method is a bound method.

I am sure there is some explanation to this behavior in Pythons documentation. Please share if you look it up 🙂

debug output

I know this question is a few years old at this point, however it was the first hit when I googled the fault.

Answered By: Alex8695
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.