How to assign a list of instance methods to a class variable?

Question:

I have this class which works:

class Point:
    def __init__(self):
        self.checks = [self.check1, self.check2]

    def check1(self):
        return True

    def check2(self):
        return True

    def run_all_checks(self):
        for check in self.checks:
            check()

The instance variable checks is not specific to instances, so I want to move it to class level, here is my attempt :

class Point:

    def __new__(cls, *args, **kwargs):
        cls.checks = [cls.check1, cls.check2]
        return super(Point, cls).__new__(cls, *args, **kwargs)

    def check1(self):
        return True

    def check2(self):
        return True

    def run_all_checks(self):
        for check in self.checks:
            check()

The class definition seems to work (in the sense that there are no syntax errors), but when I run it, got error :

TypeError: Point.check1() missing 1 required positional argument: 'self'

Update

With @juanpa.arrivillaga’s solution, my problem is solved :

class ParentFuncs:
    def check1(self):
        print("check1")

    def check2(self):
        print("check2")

    checks = [check1, check2]

    def run_all_checks(self):
        for check in self.checks:
            check(self)


class ChildFuncs(ParentFuncs):
    def check3(self):
        print("check3")

    def check4(self):
        print("check4")

    checks = ParentFuncs.checks + [check3, check4]

ChildFuncs().run_all_checks()
# Output
check1
check2
check3
check4
Asked By: Philippe

||

Answers:

Just do it in the class body, and then in run_all_checks, make sure to pass the instance explicitly, because they will just be functions, not bound methods (which get created when accessing a method through and instance):

class Point:

    def check1(self):
        return True

    def check2(self):
        return False

    checks = [check1, check2]

    def run_all_checks(self):
        for check in self.checks:
            print(check(self))


point = Point()
point.run_all_checks()

Note, this doesn’t behave the same way in the case of inheritance. But that is probably OK, depending on your use-case.

You could do something like checks = ['check1', 'check2'] and then in run_all_checks, something like getattr(self, check)(), but IMO, this is more brittle. So I would go with your original approach in that case if I intended these methods to be overridden in subclasses.

Answered By: juanpa.arrivillaga
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.