Tips and tricks¶
Preventing code duplication¶
As much as possible, it’s good to avoid copy-pasting the same code in multiple places. Although it sometimes takes a bit of thinking to figure out how to avoid copy-pasting code, you will see that having your code in only one place usually saves you a lot of effort later when you need to change the design of your code or fix bugs.
Below are some techniques to achieve code reuse.
Don’t make multiple copies of your app¶
If possible, you should avoid copying an app’s folder to make a slightly different version, because then you have duplicated code that is harder to maintain.
If you need multiple rounds, set num_rounds
.
If you need slightly different versions (e.g. different treatments),
then you should use the techniques described in Treatments,
such as making 2 session configs that have a different
'treatment'
parameter,
and then checking for self.session.config['treatment']
in your app’s code.
views.py: prevent code duplication by using multiple rounds¶
If your views.py
has many pages that are almost the same,
consider just having 1 page and looping it for multiple rounds.
One sign that your code can be simplified is if it looks
something like this:
# [pages 1 through 7....]
class Decision8(Page):
form_model = models.Player
form_fields = ['decision8']
class Decision9(Page):
form_model = models.Player
form_fields = ['decision9']
# etc...
See the quiz or real effort sample games for examples of how to just have 1 page that gets looped over many rounds, varying the question that gets displayed with each round.
views.py: prevent code duplication by using inheritance¶
If you can’t merge your code into 1 Page as suggested above, but your code still has a lot of repetition, you can use Python inheritance to define the common code on a base class.
Basic example¶
For example, let’s say that your page classes all
repeat some of the code, e.g. the is_displayed
condition:
class Page1(Page):
def is_displayed(self):
return self.player.foo
...
class Page2(Page):
def is_displayed(self):
return self.player.foo
...
class Page3(Page):
def is_displayed(self):
return self.player.foo
...
page_sequence = [
Page1,
Page2,
Page3,
]
You can eliminate this repetition as follows:
class BasePage(Page):
def is_displayed(self):
return self.player.foo
class Page1(BasePage):
pass
class Page2(BasePage):
pass
class Page3(BasePage):
pass
page_sequence = [
Page1,
Page2,
Page3,
]
(This is not a special oTree feature; it is simply using Python class inheritance.)
More complex example¶
Let’s say you’ve got the following code (note that Page1
passes an extra
variable 'd'
):
class Page1(Page):
def vars_for_template(self):
return {
'a': 1,
'b': 2,
'c': 3,
'd': 4
}
class Page2(Page):
def vars_for_template(self):
return {
'a': 1,
'b': 2,
'c': 3
}
class Page3(Page):
def vars_for_template(self):
return {
'a': 1,
'b': 2,
'c': 3
}
You can refactor this as follows:
class BasePage(Page):
def vars_for_template(self):
v = {
'a': 1,
'b': 2,
'c': 3
}
v.update(self.extra_vars_for_template())
return v
def extra_vars_for_template(self):
return {}
class Page1(BasePage):
def extra_vars_for_template(self):
return {'d': 4}
class Page2(BasePage):
pass
class Page3(BasePage):
pass