pythonclassmethodsproject-structure

Access Python Class Attribute inside externally called method


In a case like:

class Foo(object):
    def __init(self, x):
        self.var = x

    def loop(self):
        # [yield params]
        result = self.do_sth(params)

    def do_sth(self, params):
        if self.var is not None:
            bar(params)
        if self.var > 1:
            do_other_bar(params)

if __name__ == '__main__':
    foo = Foo(2)

In my project i have a class consisting of a lot of methods, so I want to move the do_sth method outside (e.g. into another module):

# mymodule.py
def do_sth_external(params, var):
    if var is not None:
        bar()
    if var > 1:
        do_other_bar()
from mymodule import do_sth_external
class Foo(object):
    def __init(x):
        self.var = x

    def loop():
        # [yield params]
        result = do_sth_external(params, self.var)

if __name__ == '__main__':
    foo = Foo(2)

what other ways are there to break down a huge class?


Edit: whatever reason someone thought this question was opinion based. It is asking for best practices...


Solution

  • Without agreeing or disagreeing that splitting up a class like this is a good idea, the right approach would be to simply define the method like you always do, and simply assign the function to the appropriate class attribute.

    class Foo(object):
        def __init(self, x):
            self.var = x
    
        def loop(self):
            # [yield params]
            result = self.do_sth(params)
    
        def do_sth(self, params):
            if self.var is not None:
                bar(params)
            if self.var > 1:
                do_other_bar(params)
    

    becomes

    # Defined here or in another module, it doesn't matter.
    # With the exception of the name the function is bound to,
    # nothing else has changed.
    def foo_do_sth(self, params):
        if self.var is not None:
            bar(params)
        if self.var > 1:
            do_other_bar(params)
    
    
    class Foo(object):
        def __init(self, x):
            self.var = x
    
        def loop(self):
            # [yield params]
            result = self.do_sth(params)
    
        do_sth = foo_do_sth
    

    There's nothing special about a function definition in a class statement; the only important thing is that a name in the namespace of the class statement be assigned an appropriate value. (The metaclass will use all names defined in the class statement to add attributes to the resulting class, and an instance method is nothing more than a function-valued class attribute.)


    From time to time, there have been various proposals to allow things like

    class Foo:
        ...
    
    def Foo.do_sth(self, params):
        ...
    

    to facilitate adding methods to a class after it has been created. This is because it's already possible to use assignment statements like

    def do_sth(self, params):
        ...
    
    Foo.do_sth = do_sth
    

    and it's felt that other statements that perform assignments should be able to assign to attributes as well.