Modeling a class with a metaclass
class Meta(type):
def __new__(mcs, name, bases, namespace, **kwargs):
if not [base for base in bases if isinstance(base, mcs)]:
return super().__new__(mcs, name, bases, namespace, **kwargs)
annotations = namespace.get('__annotations__', {})
namespace["__slots__"] = tuple(annotations.keys()) # auto __slots__
return super().__new__(mcs, name, bases, namespace, **kwargs)
def __call__(cls, **kwargs):
for field_name, field_type in cls.__annotations__.items():
if field_name not in kwargs:
raise ValueError(f"Missing field {field_name}")
else:
assert isinstance(kwargs[field_name], field_type), f"Field {field_name} must be of type {field_type}"
for field_name, field_value in kwargs.items():
if field_name not in cls.__annotations__:
raise ValueError(f"Unknown field {field_name}")
return super().__call__(**kwargs)
class BaseModel(metaclass=Meta):
def __init__(self, **kwargs):
for field_name, field_value in kwargs.items():
setattr(self, field_name, field_value)
class Account(BaseModel):
first_name: str
last_name: str
username: str
account = Account(first_name="Hakan", last_name="Çelik", username="hakancelik")
assert account.__slots__ == ("first_name", "last_name", "username")
assert account.__dict__ == {}
assert account.first_name == "Hakan"
assert account.last_name == "Çelik"
assert account.username == "hakancelik"
# Account(first_name="Hakan", last_name="Çelik", username=1)
Last update: June 2, 2023
Created: June 2, 2023
Created: June 2, 2023