parallax icon indicating copy to clipboard operation
parallax copied to clipboard

Removing @decorators.

Open synchronizing opened this issue 5 years ago • 0 comments

As mentioned here, the following will remove the need to use decorators everywhere:

import typing

class Module():    
    def __new__(cls, *args, **kwargs):
 
        type_hints = typing.get_type_hints(cls)
        arguments = {}
        
        # Takes care of the kwargs terms.
        for name, value in kwargs.items():
            if name not in type_hints:
                raise Exception("Param given was not explicitly defined.")
            elif isinstance(value, type_hints[name]):
                arguments[name] = value
                type_hints.pop(name)
            else:
                raise Exception("Not of valid type.")

        # Takes care of the leftover args. 
        for value, type_hint_name, type_hint_type in zip(args, type_hints.keys(), type_hints.values()):
            if isinstance(value, type_hint_type):
                arguments[type_hint_name] = value
            else:
                raise Exception("Not of valid type.")

        # Initiate the class.
        initiated_cls = super().__new__(cls)
        
        # Updates the object arguments.
        initiated_cls.__dict__.update(arguments)
        
        return initiated_cls
    
    # Does not allow any attribute setting.
    def __setattr__(self, attr, val):
        raise Exception("Cannot modify the class.")
    
    @classmethod
    def init(cls, *args, **kwargs):
        return Module.__new__(cls, *args, **kwargs)

With the above we now have type hint checking (in other words setting var1: str bellow will throw error when setup() is called with an int type); __init__ behaviour via static setup(); and and class freeze via overwriting __setattr__:

class Dense(Module):

    var1: int
    var2: int
    var3: int

    def setup(param1, param2, param3):
        return Dense.init(param1, param2, var3=param3)

    def forward(self):
        return self.var1 + self.var2

Use:

dense = Dense.setup(10, 11, param3=13) # Works as expected.
dense.forward() # Returns 21 as expected.

dense = Dense.setup("str", 11, param3=13) # Throws exception on type check (var1: int).
dense.var3 = 10 # Throws exception. 
dense.var4 = 10 # Throws exception. 

synchronizing avatar May 20 '20 21:05 synchronizing