Skip to content

Instantly share code, notes, and snippets.

@tempKDW
Created December 7, 2018 06:27
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save tempKDW/cff2bbb38e499d7196f5cc2a0c3b628c to your computer and use it in GitHub Desktop.
Save tempKDW/cff2bbb38e499d7196f5cc2a0c3b628c to your computer and use it in GitHub Desktop.
strict type checking with data class
class DataMeta(type):
def __new__(cls, name, bases, attrs):
def restrict_set_new_key(k):
if k not in attrs:
raise KeyError('not allowed setting new key')
def check_type(k, v):
cls._validate(attrs[k]['type'], v)
def set_default(self, kwargs):
for key_meta, value_meta in attrs.items():
if key_meta.startswith('__') and key_meta.endswith('__'):
continue
if not isinstance(value_meta, dict):
continue
if key_meta not in kwargs and 'default' in value_meta:
self.__dict__[key_meta] = value_meta['default']
elif key_meta not in kwargs and 'default' not in value_meta:
raise ValueError('{} is required.'.format(key_meta))
def setattr_(self, k, v):
restrict_set_new_key(k)
check_type(k, v)
self.__dict__[k] = v
def init(self, **kwargs):
for k, v in kwargs.items():
setattr_(self, k, v)
set_default(self, kwargs)
attrs['__setattr__'] = setattr_
attrs['__init__'] = init
return type(name, bases, attrs)
@staticmethod
def _validate(type_, value):
if not isinstance(value, type_):
raise ValueError
class OrderData(metaclass=DataMeta):
number = {'type': str}
price = {'type': int}
commission = {'type': float, 'default': 1.1}
def get_total_price(self):
return self.price * self.commission
if __name__ == '__main__':
o = OrderData(number='10', price=100)
print(o.number)
print(o.commission)
print(o.price)
print(o.get_total_price())
o.foo = 10
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment