-2

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?

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Himanshu97
  • 541
  • 1
  • 9
  • 19

2 Answers2

2

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.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
  • i did the same, error came : Inventory not defined (i.e. class name) – Himanshu97 Aug 08 '14 at 13:46
  • yeah, workaround was always possible, i just cant figure it out yet, why previous code wasnt working, when a name error for class name came. PS. thanx for your efforts – Himanshu97 Aug 08 '14 at 14:01
  • I have explained that at the start of my answer – jonrsharpe Aug 08 '14 at 14:03
  • Yes it works, but somebody knows, why cant I use setattr inside this calculate_total_stock function. setattr does not throw any error, but doesnt work either. – Nikolai Ehrhardt Aug 17 '22 at 07:40
  • @NikolaiEhrhardt with so little context it's impossible to say. – jonrsharpe Aug 17 '22 at 07:44
  • Actually I dont want to raise new question, we redefine now calculate_total_stock: 1.) load json, 2.) do setattr(class, key, value) for json.items(). With a forward declaration of class it doesnt throw any error, but doesnt work either. – Nikolai Ehrhardt Aug 17 '22 at 07:49
2

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.

Alex8695
  • 479
  • 2
  • 5