pythonvalidationmetaclassclass-constructors

Optimizing Input Verification in Nested Class Methods


I have the following example class:

class MyClass:
    @classmethod
    def method1(cls, value):
        print(f'method1 called with value: {value}')
        cls.method2(value)
        cls.method3(value)

    @classmethod
    def method2(cls, value):
        print(f'method2 does something with supplied value: {value}')

    @classmethod
    def method3(cls, value):
        print(f'method3 does something with supplied value: {value}')

As you can see, there is a nested logic here. method1 has to call the methods method2 and method3. Now, every time any of the methods (I have many more) is called, I want to verify the input value. I could define a classmethod and then call cls._verify(cls, value) at the beginning of each function. However, this will mean that my input will be verified mulitple times.

How can I efficiently perform input verification for a set of class methods, including nested calls, without redundantly verifying the input multiple times?

I tried: (1) I tried adding a "cache" argument (i.e. cls._already_verified) that would be turned to True after verification. The problem with this approach is that the next time another method of my class is runned, the value is still True. Also, (2) only calling a _verify method in public classes would not work, because many of the methods build on other publicly available method.


Solution

  • You could separate the logic of your methods into a public and a private layer. The public layer is responsible for verifying the inputs and otherwise delegates to the private layer, and the private layer trusts that the inputs are already verified and is responsible for the actual application logic.

    The private methods can freely call each other without the verification overhead. The public methods should only call private methods after the inputs are verified, but not call other public methods.

    class MyClass:
        @classmethod
        def method1(cls, value):
            print(f'method1 called with value: {value}')
            cls._verify(value)
            cls._method2_no_verify(value)
            cls._method3_no_verify(value)
    
        @classmethod
        def method2(cls, value):
            cls._verify(value)
            cls._method2_no_verify(value)
    
        @classmethod
        def method3(cls, value):
            cls._verify(value)
            cls._method3_no_verify(value)
    
        @classmethod
        def _method2_no_verify(cls, value):
            print(f'method2 does something with supplied value: {value}')
    
        @classmethod
        def _method3_no_verify(cls, value):
            print(f'method3 does something with supplied value: {value}')