Skip to content

Instantly share code, notes, and snippets.

@falsetru
Forked from tempKDW/datameta.py
Last active Dec 7, 2018
Embed
What would you like to do?
Use `new_attrs` when creating __slots__
class DataMeta(type):
def __new__(cls, name, bases, attrs):
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:
setattr(self, 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):
if k in attrs:
check_type(k, v)
object.__setattr__(self, k, v)
def init(self, **kwargs):
for k, v in kwargs.items():
setattr_(self, k, v)
set_default(self, kwargs)
new_attrs = {name: value for name, value in attrs.items() if name.startswith('__') or callable(value)}
new_attrs['__slots__'] = [name for name in attrs if name not in new_attrs]
new_attrs['__setattr__'] = setattr_
new_attrs['__init__'] = init
return type(name, bases, new_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