I have a doubt in understanding statement
name = SizedRegexString(maxlen=8, pat='[A-Z]+$')
in the code below. I am not able to understand how init calls are happening up in the hierarchy.
# Example of defining descriptors to customize attribute access.
from inspect import Parameter, Signature
import re
from collections import OrderedDict
class Descriptor:
def __init__(self, name=None):
print("inside desc")
self.name = name
def __set__(self, instance, value):
instance.__dict__[self.name] = value
def __delete__(self, instance):
raise AttributeError("Can't delete")
class Typed(Descriptor):
ty = object
def __set__(self, instance, value):
if not isinstance(value, self.ty):
raise TypeError('Expected %s' % self.ty)
super().__set__(instance, value)
class String(Typed):
ty = str
# Length checking
class Sized(Descriptor):
def __init__(self, *args, maxlen, **kwargs):
print("inside sized")
self.maxlen = maxlen
super().__init__(*args, **kwargs)
def __set__(self, instance, value):
if len(value) > self.maxlen:
raise ValueError('Too big')
super().__set__(instance, value)
class SizedString(String, Sized):
pass
# Pattern matching
class Regex(Descriptor):
def __init__(self, *args, pat, **kwargs):
print("inside regex")
self.pat = re.compile(pat)
super().__init__(*args, **kwargs)
def __set__(self, instance, value):
if not self.pat.match(value):
raise ValueError('Invalid string')
super().__set__(instance, value)
class SizedRegexString(SizedString, Regex):
pass
# Structure definition code
def make_signature(names):
return Signature(
Parameter(name, Parameter.POSITIONAL_OR_KEYWORD)
for name in names)
class StructMeta(type):
@classmethod
def __prepare__(cls, name, bases):
return OrderedDict()
def __new__(cls, clsname, bases, clsdict):
fields = [key for key, val in clsdict.items()
if isinstance(val, Descriptor) ]
for name in fields:
clsdict[name].name = name
clsobj = super().__new__(cls, clsname, bases, dict(clsdict))
sig = make_signature(fields)
setattr(clsobj, '__signature__', sig)
return clsobj
class Structure(metaclass=StructMeta):
def __init__(self, *args, **kwargs):
bound = self.__signature__.bind(*args, **kwargs)
for name, val in bound.arguments.items():
setattr(self, name, val)
if __name__ == '__main__':
class Stock(Structure):
name = SizedRegexString(maxlen=8, pat='[A-Z]+$')
for item in SizedRegexString.__mro__:
print(item)
Output from print statements inside init:
inside sized
inside regex
inside desc
inside desc
inside desc
Output from mro of SizedRegexString class
<class '__main__.SizedRegexString'>
<class '__main__.SizedString'>
<class '__main__.String'>
<class '__main__.Typed'>
<class '__main__.Sized'>
<class '__main__.Regex'>
<class '__main__.Descriptor'>
<class 'object'>
Does init and set both call chains follow the mro? Or there is something else happening here?
