-1

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...

gorschel
  • 26
  • 8
  • If `do_sth()` really needs the `self` then it should be back in the class. If your real name for `do_sth()` is really descriptive and specific, (and it is used by other parts of your code) then it is worth moving to its own module. – quamrana Apr 18 '23 at 16:54

1 Answers1

1

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.

chepner
  • 497,756
  • 71
  • 530
  • 681