Question: I have a scenario where I have objects with static methods. They are all built using an outside def build_hello() as class variables. def build_hello(name: str): @staticmethod def hello_fn(): return "hello my name is " # Assign an attribute to the staticmethod so it can be used across all classes hello_fn.first_name = name print(hello_fn() + hello_fn.first_name) # This works return hello_fn class World: hello_fn = build_hello("bob") # Error, function object has no attribute "first_name" World.hello_fn.first_name  What is happening here? I am able to access the attribute of hello_fn() within the build_hello() function call. but when its added to my object, that attribute no longer lists. Also if I call dir() on the static method. I do not see it present: dir(World.hello_fn) ['__annotations__', '__builtins__', '__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__', '__getstate__', '__globals__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__kwdefaults__', '__le__', '__lt__', '__module__', '__name__', '__ne__', '__new__', '__qualname__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__type_params__'] 

Answer: Method retrieving from a class, in Python, be it regular instance methods, class methods or static methods, use an underlying mechanism to actually build the method object at the time it is requested (usually with the . operator, but also with a getattr(...) call): The objects that are bound to class namespaces have a __get__ method - it is this __get__ which builds the object that is retrieved and that will be called as the method - so, if it is a classmethod, the cls is inserted as first parameter, or the self argument for regular methods, and nothing inserted for staticmethods. The thing is that the __get__ method for a regular function will make it behave like a common instance methods. The @classmethod and @staticmethod decorators have a different behavior for the __get__ method which produce the desired final effects when calling the method. So, when you create a staticmethod wrapping your function, it is not this object that is retrieved when you do MyClass.mymethod - rather, it is whatever the __get__ method of @staticmethod returns - in this case, it returns the underlying function as is. TL;DR: put your attributes in the underlying function, before wrapping it with the staticmethod call, as that is what is returned by World.hello_fn: def build_hello(name: str): def hello_fn(): return "hello my name is " # Assign an attribute to the staticmethod so it can be used across all classes hello_fn.first_name = name print(hello_fn() + hello_fn.first_name) # This works return staticmethod(hello_fn) # Just wrap the function with the staticmethod decorator here! class World: hello_fn = build_hello("bob") World.hello_fn.first_name  Alternatively, you can reach the function after applying the decorator through the attribute __func__ of the staticmethod object: def build_hello(name: str): @staticmethod def hello_fn(): return "hello my name is " hello_fn.__func__.first_name = name return hello_fn