8.1. Metaprogramming Init Subclass
Created for the people, to reduce times when you need metaclasses
class Account:
def __init_subclass__(cls, **kwargs):
super().__init_subclass__(**kwargs)
8.1.1. Example
class Account:
def __init_subclass__(cls, **kwargs):
print('Account init_subclass')
class User(Account):
pass
Account init_subclass
8.1.2. Arguments
class Account:
def __init_subclass__(cls, debug=False, **kwargs):
print(f'Account init_subclass: {debug=}')
Creating class without specifying the argument will use the default value:
class User(Account):
pass
Account init_subclass: debug=False
Now, let's pass the argument to the subclass:
class User(Account, debug=True):
pass
Account init_subclass: debug=True
8.1.3. Use Case - 1
from uuid import uuid4
from datetime import datetime, timezone
from pprint import pprint
class Account:
def __init_subclass__(cls, debug=False, **kwargs):
if debug:
cls._uuid = uuid4()
cls._since = datetime.now(timezone.utc)
class User(Account):
pass
pprint(vars(User))
mappingproxy({'__doc__': None,
'__firstlineno__': 1,
'__module__': '__main__',
'__static_attributes__': ()})
class User(Account, debug=True):
pass
pprint(vars(User))
mappingproxy({'__doc__': None,
'__module__': '__main__',
'_since': datetime.datetime(2024, 8, 20, 14, 55, 59, 764071, tzinfo=datetime.timezone.utc),
'_uuid': UUID('6d1bc92c-ddb6-47cb-a872-24f94f3d1be4')})
8.1.4. Use Case - 2
import string
string.ascii_uppercase
'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
tuple(string.ascii_uppercase)
('A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z')
class Account:
def __init_subclass__(cls, strict=False, **kwargs):
if strict:
uppercase = tuple(string.ascii_uppercase)
assert cls.__name__.startswith(uppercase), \
'Class name must start with uppercase letter'
super().__init_subclass__()
class user(Account):
pass
class user(Account, strict=True):
pass
Traceback (most recent call last):
AssertionError: Class name must start with uppercase letter
class User(Account):
pass
class User(Account, strict=True):
pass
8.1.5. Use Case - 3
from pprint import pprint
class PositionMixin:
def __init_subclass__(cls, **kwargs):
cls.position_x = 0
cls.position_y = 0
super().__init_subclass__(**kwargs)
class HealthMixin:
def __init_subclass__(cls, **kwargs):
cls.health = 100
super().__init_subclass__(**kwargs)
class Hero(PositionMixin, HealthMixin):
def __init__(self, name):
self.name = name
hero = Hero('Twardowski')
hero.position_x
0
hero.position_y
0
hero.health
100
vars(hero)
{'name': 'Twardowski'}
pprint(vars(Hero))
mappingproxy({'__doc__': None,
'__firstlineno__': 1,
'__init__': <function Hero.__init__ at 0x...>,
'__module__': '__main__',
'__static_attributes__': ('name',),
'health': 100,
'position_x': 0,
'position_y': 0})