I recently started to work with Python’s classes, since I need to work with it through the use of OTree, a Python framework used for online experiment.
In one file, I define the pages that I want to be created, using classes. So essentially, in the OTree system, each class corresponds to a new page. The thing is, all pages (so classes) are basically the same, at the exception to some two parameters, as shown in the following code:
class Task1(Page): form_model = 'player' form_fields = ['Envie_WordsList_Toy'] def is_displayed(self): return self.round_number == self.participant.vars['task_rounds'][1] def vars_for_template(player): WordsList_Toy= Constants.WordsList_Toy.copy() random.shuffle(WordsList_Toy) return dict( WordsList_Toy=WordsList_Toy ) @staticmethod def live_method(player, data): player.WTP_WordsList_Toy = int(data) def before_next_page(self): self.participant.vars['Envie_WordsList_Toy'] = self.player.Envie_WordsList_Toy self.participant.vars['WTP_WordsList_Toy'] = self.player.WTP_WordsList_Toy
So here, the only thing that would change would be the name of the class, as well as the suffix of the variable WordsList_
used throughout this code, which is Toy
.
Naively, what I tried to do is to define a function that would take those two parameters, such as this:
def page_creation(Task_Number,name_type): class Task+str(Task_Number)(Page): form_model = 'player' form_fields = ['Envie_WordsList_'+str(name_type)] def is_displayed(self): return self.round_number == self.participant.vars['task_rounds'][1] def vars_for_template(player): WordsList_+str(name_type) = Constants.WordsList+str(name_type).copy() random.shuffle(WordsList_+str(name_type)) return dict( WordsList_+str(name_type)=WordsList_+str(name_type) ) @staticmethod def live_method(player, data): player.WTP_WordsList_+str(name_type) = int(data) def before_next_page(self): self.participant.vars['Envie_WordsList_+str(name_type)'] = self.player.Envie_WordsList_+str(name_type) self.participant.vars['WTP_WordsList_+str(name_type)'] = self.player.WTP_WordsList_+str(name_type)
Obviously, it does not work since I have the feeling that it is not possible to construct variables (or classes identifier) this way. I just started to really work on Python some weeks ago, so some of its aspects might escape me still. Could you help me on this issue? Thank you.
Advertisement
Answer
You can generate dynamic classes using the type
constructor:
MyClass = type("MyClass", (BaseClass1, BaseClass2), {"attr1": "value1", ...})
Thus, according to your case, that would be:
cls = type(f"Task{TaskNumber}", (Page, ), {"form_fields": [f"Envive_WordList_{name_type}"], ...})
Note that you still have to construct your common methods like __init__
, is_displayed
and so on, as inner functions of the class factory:
def class_factory(*args, **kwargs): ... def is_displayed(self): return self.round_number == self.participant.vars['task_rounds'] def vars_for_template(player): ... # Classmethod wrapping is done below def live_method(player, data): ... cls = type(..., { "is_displayed": is_displayed, "vars_for_template": vars_for_template, "live_method": classmethod(live_method), ..., }
@classmethod
could be used as a function – {"live_method": classmethod(my_method)}