3

If I have a class Foo with the method method1, is there a way to store this method in a variable before instantiation, which I then could call after this class is instantiated?

For example:

class Foo:
    def method1(self, arg):
        print(self, arg)

# something like this variable, but which can be called with instantiated class 
func = Foo.method1

foo = Foo()
foo.func(1)  # I want to call it in a similar way to this
Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
M.T
  • 4,917
  • 4
  • 33
  • 52
  • Oh, I never realized that methods behaved in that way for uninstantiated classes. This answers my question. – M.T Jan 23 '18 at 18:22
  • I'm planning to use this question as a duplicate target in the future, so I've touched it up a little to make it shorter and more to the point. – Aran-Fey Jan 24 '18 at 09:41

2 Answers2

1

In python, there is no real distinction between functions and methods - a method is merely a function defined in a class.

For us, this means that the function stored in the variable func can be called like any other function. If func refers to Foo.method1, it's a function with 2 parameters: self and arg. In order to invoke func, we simply pass a Foo instance as the self argument and another value as the arg argument:

func(foo, 1)

The reason why we usually don't have to pass an argument for self is because accessing the method through an instance automatically turns the function method1 into a bound method, where the self argument is passed implicitly:

>>> Foo.method1  # Foo.method1 is a function
<function Foo.method1 at 0x7f9b3c7cf0d0>
>>>
>>> foo.method1  # but foo.method1 is a bound method!
<bound method Foo.method1 of <__main__.Foo object at 0x7f9b3c7dd9e8>>

For more details about functions and methods, see this question.

Aran-Fey
  • 39,665
  • 11
  • 104
  • 149
1

In addition to Rawing's excellent answer, you may not need to instantiate the class if all you're accessing is a static or class attribute:

class Container:
    class_var = "class_var"
    def __init__(self, inst_var):
        self.inst_var = inst_var
        print("Instantiated")

    @staticmethod
    def static_mtd(static_arg):
        print(static_arg)

    def instance_mtd(self):
        print(self.inst_var)

    @classmethod
    def class_mtd(cls):
        print(cls.class_var)

stat = Container.static_mtd
stat("static_arg")  # static_arg

inst = Container.instance_mtd
inst(Container("inst_var"))   # Instantiated, inst_var

inst2 = Container("inst_var2").instance_mtd   # Instantiated
inst2()  # inst_var2

clas = Container.class_mtd
clas()  # class_var

var = Container.class_var # class_var

So, you can assign the variable name inst to an instance method Container.instance_mtd first, instantiate the class later on, and feed the instantiated class back into inst as the self argument. This is of course rather tedious, and it means that your reassigned instance method is effectively defined outside of the class.

Melvin
  • 1,530
  • 11
  • 18