parallax
parallax copied to clipboard
Removing @decorators.
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.