Search code examples
pythonpython-3.xcallablecallable-object

How to execute function if class instance is passed?


I currently have a TestClass that is callable. The callable executes a function that raises an exception if any attribute is equal to None. The purpose of defining it to be callable is so when TestClass instance is passed to another function or copied, it will perform a check that all attributes exist prior to being passed, else it will raise an exception.

The line below that exhibits this logic is UsesTestClass(testClass()).

Ideally I want to be able to perform the same check without having to "call" the class instance. For example, UsesTestClass(testClass). Is there a magic method or some other way to configure the class to be able to execute a function prior to being passed as an argument?

class TestClass:
    def __init__(self):
        self.name = None

    def run(self):
        if self.name is None:
            raise Exception("'name' attribute is 'None'")

    def __call__(self):
        self.run()
        return self

def UsesTestClass(testClass):
    print(testClass.name)

testClass = TestClass()
testClass.name = "Hello"
UsesTestClass(testClass())

Solution

  • If you use the types library integrated into python you can do this.

    import types
    
    
    class TestClass:
        def __init__(self):
            self.name = None
    
        def __getattribute__(self, attr):
            method = object.__getattribute__(self, attr)
            if not method:
                raise Exception("Attribute %s not implemented" % attr)
            if type(method) == types.MethodType:
                self.run()
            return method
    
        def run(self):
            if self.name is None:
                raise Exception("'name' attribute is 'None'")
    
        def __call__(self):
            self.run()
            return self
    
    
    def UsesTestClass(testClass):
        print(testClass.name)
    
    
    testClass = TestClass()
    testClass.name = "Hello"
    UsesTestClass(testClass)