Je joue un peu avec la métaprogrammation Python.
class FormMetaClass(type):
def __new__(cls, clsname, bases, methods):
# Attach attribute names to the descriptors
for key, value in methods.items():
if isinstance(value, FieldDescriptor):
value.name = key
return type.__new__(cls, clsname, bases, methods)
class Form(metaclass=FormMetaClass):
@classmethod
def from_json(cls, incoming):
instance = cls()
data = json.loads(incoming)
for k, v in data.items():
if (not hasattr(instance, k)):
raise KeyError("Atrribute not found")
instance.__setattr__(k, v)
return cls
class MyForm(Form):
first_name = String()
last_name = String()
age = Integer()
def __repr__(self):
return "{} {}".format(self.first_name, self.last_name)
def main():
data = json.dumps({'first_name': 'Thomas',
'last_name': 'Junk'})
form = MyForm.from_json(data)
print(form)
if __name__ == "__main__":
main()
class FieldDescriptor:
def __init__(self, name=None, **opts):
self.name = name
for key, value in opts.items():
setattr(self, key, value)
def __set__(self, instance, value):
instance.__dict__[self.name] = value
class Typechecked(FieldDescriptor):
expected_type = type(None)
def __set__(self, instance, value):
if not isinstance(value, self.expected_type):
raise TypeError('expected ' + str(self.expected_type))
super().__set__(instance, value)
class Integer(Typechecked):
expected_type = int
class String(Typechecked):
expected_type = str
J'ai un Form
qui possède une métaclasse FormMetaClass
. Pour disposer d'un constructeur alternatif, j'utilise un constructeur de type @classmethod
. Je crée un instance
qui semblent fonctionner jusqu'à présent.
Ce qui ne fonctionne pas, c'est l'appel à la fonction __repr__
(ou __str__
de manière interchangeable). Lorsque je crée une instance via MyForm()
tout va bien. Lorsque je crée une instance via la fonction @classmethod
une mise en œuvre "par défaut" est adoptée.
Je m'attendais à Thomas Junk
mais j'obtiens <class '__main__.MyForm'>
Pourriez-vous me donner un indice sur ce que je néglige ?