patternpythonMinor
Reflecting emotion classification based on the Lövheim cube
Viewed 0 times
emotionthelövheimbasedreflectingcubeclassification
Problem
Background
I created a simple class to reflect emotion classification based on the Lövheim cube. The code is not scientific at all, and I just did it for fun, but I want all code I write to be as Pythonic and efficient as possible, so I was hoping for some help refactoring it.
Code Purpose
Class
Review Goals
I am hoping to make my code as efficient and readable as possible, so any advice is welcomed.
```
class Emoter:
"""
Create an instance of the class with a name.
Use set_levels to set neurotransmitter levels for dopamine, serotonin, and noradrenaline.
Check current emotion with emotion attribute.
"""
def __init__(self, name):
self.name = name
self.status = "alive"
self.thresholds = {}
self.level = {}
self.count = {}
self.thresholds["dopamine"] = [0, 25, 75, 100]
self.thresholds["noradrenaline"] = [0, 25, 75, 100]
self.thresholds["serotonin"] = [0, 25, 75, 100]
self.level["dopamine"] = "normal"
self.level["noradrenaline"] = "normal"
self.level["serotonin"] = "normal"
self.count["dopamine"] = 1
self.count["noradrenaline"] = 1
self.count["serotonin"] = 1
self.emotion = "NEUTRAL"
def __adjust_thresholds(self, neurotransmitter):
"""
Adjusts thresholds for neurotransmitter level evaluations.
A very rudimentary function meant to reflect the effects of LTP and LTD.
Sort of.
"""
if self.count[neurotransmitter] > 3:
if self.level[neurotransmitter] is "low":
print(self.name + "'s " + neurotransmitter + " levels have " +
I created a simple class to reflect emotion classification based on the Lövheim cube. The code is not scientific at all, and I just did it for fun, but I want all code I write to be as Pythonic and efficient as possible, so I was hoping for some help refactoring it.
Code Purpose
Class
Emoter takes in serotonin, dopamine, and noradrenaline levels and determines the emotion of the emoter via the set_levels function. Thresholds for what are considered "high", "low", and "normal" levels of each neurotransmitter change depending on past experience, and values outside of acceptable ranges kill the Emoter.Review Goals
I am hoping to make my code as efficient and readable as possible, so any advice is welcomed.
```
class Emoter:
"""
Create an instance of the class with a name.
Use set_levels to set neurotransmitter levels for dopamine, serotonin, and noradrenaline.
Check current emotion with emotion attribute.
"""
def __init__(self, name):
self.name = name
self.status = "alive"
self.thresholds = {}
self.level = {}
self.count = {}
self.thresholds["dopamine"] = [0, 25, 75, 100]
self.thresholds["noradrenaline"] = [0, 25, 75, 100]
self.thresholds["serotonin"] = [0, 25, 75, 100]
self.level["dopamine"] = "normal"
self.level["noradrenaline"] = "normal"
self.level["serotonin"] = "normal"
self.count["dopamine"] = 1
self.count["noradrenaline"] = 1
self.count["serotonin"] = 1
self.emotion = "NEUTRAL"
def __adjust_thresholds(self, neurotransmitter):
"""
Adjusts thresholds for neurotransmitter level evaluations.
A very rudimentary function meant to reflect the effects of LTP and LTD.
Sort of.
"""
if self.count[neurotransmitter] > 3:
if self.level[neurotransmitter] is "low":
print(self.name + "'s " + neurotransmitter + " levels have " +
Solution
Various comments in random-ish order.
Main guard
It is common to put your code "actually doing something" behind an
Data over code
Because of many different things, your code contains a small amount of data diluated in a large amount of text. Among the different useful techniques to make things easier to maintain is to extract the data in the relevant data structure.
For instance, you could rewrite
I also took this chance to change the order of the emotions to make it clear that what we have is a truth table.
Using the right type
You are using string all over the place, making things quite hard to follow.
-
-
the different levels shoud probably be an enum (or integers 0, 1 and 2 if you don't have
Using
In many places, you have
Compare values with
Nothing to add here.
Define your dictionnaries directly
In your
Using
Data not in the right order
Each neurotransmitter is roughtly the same but the information about it is spread in multiple dictionnary. It could be worth accessing the element in the other order (so that for instance, for "dopamine", you get all the information in a same place).
Your code now looks like :
```
class Transmitter:
def __init__(self, name):
self.name = name
self.thresholds = [0, 25, 75, 100]
self.level = 1
self.count = 1
def __adjust_threshold(self, subj):
if self.count > 3:
if self.level is "low":
print(subj + "'s " + self.name + " levels have been " + self.level + " lately, resulting in decreased sensitivity.")
self.thresholds[1] += 1
if self.thresholds[1] + 1 >= self.thresholds[2]:
self.thresholds[2] += 1
elif self.level is "high":
print(subj + "'s " + self.name + " levels have been " + self.level + " lately, resulting in increased sensitivity.")
self.thresholds[2] += - 1
if self.thresholds[2] + 1 5:
if (self.level is "normal" and
self.thresholds[2] self.thresholds[0] + 1):
print(subj + "'s " + self.name + " levels have been " + self.level + " lately, resulting in increased resilience.")
self.thresholds[2] += 1
self.thresholds[1] += -1
def adjust_levels(self, level, subj):
if self.thresholds[0] <= level < self.thresholds[1]:
self.__add_count("low")
self.level = "low"
self.__adjust_threshold(subj)
elif self.thresholds[1] <= level < self.thresholds[2]:
self.__add_count("normal")
self.level = "normal"
self.__adjust_threshold(subj)
elif self.thresholds[2] <= level < self.thresholds[3]:
self.__add_count("high")
self.level = "high"
self.__adjust_threshold(subj)
else:
return False
return True
def __add_count(self, level):
Main guard
It is common to put your code "actually doing something" behind an
if __name__ == "__main__": test.Data over code
Because of many different things, your code contains a small amount of data diluated in a large amount of text. Among the different useful techniques to make things easier to maintain is to extract the data in the relevant data structure.
For instance, you could rewrite
__determine_emotion with a simple map mapping values to emotion :def __determine_emotion(self):
"""
This needs emotions for when one or more neurotransmitters are within
normal ranges.
"""
emo_dict = {
("high", "high", "high"): "INTEREST/EXCITEMENT",
("high", "high", "low") : "ANGER/RAGE",
("high", "low", "high"): "ENJOYMENT/JOY",
("low", "high", "high"): "SURPRISE",
("low", "high", "low") : "CONTEMPT/DISGUST",
("low", "low", "high"): "DISTRESS/ANGUISH",
("low", "low", "low") : "SHAME/HUMILIATION",
}
levels = (self.level["dopamine"], self.level["noradrenaline"], self.level["serotonin"])
self.emotion = emo_dict.get(levels, "NEUTRAL")I also took this chance to change the order of the emotions to make it clear that what we have is a truth table.
Using the right type
You are using string all over the place, making things quite hard to follow.
-
self.status should probably be a boolean (with a different name)-
the different levels shoud probably be an enum (or integers 0, 1 and 2 if you don't have
enum on your version).Using
+=In many places, you have
a_variable_with_a_super_long_name = a_variable_with_a_super_long_name + n. This can be written : a_variable_with_a_super_long_name += n.Compare values with
==Nothing to add here.
Define your dictionnaries directly
In your
__init__ method, you can simply write :self.thresholds = {
"dopamine": [0, 25, 75, 100],
"noradrenaline": [0, 25, 75, 100],
"serotonin": [0, 25, 75, 100],
}
self.level = {
"dopamine": "normal",
"noradrenaline": "normal",
"serotonin": "normal",
}
self.count = {
"dopamine": 1,
"noradrenaline": 1,
"serotonin": 1,
}in range is not what you needUsing
x in range(a, b) is not the right way to check whether x is bigger (or equal) than a while being smaller than b. Indeed, this can be simply written a <= x and x < b (as in most languages) or a <= x < b (quite specific to Python). In you want to understand why in range is not the right way to do, try to consider what it actually does behind the scene. If that's not enough, compare 0 in range(1, 100000000) to 1 <= 0 < 100000000. (This is true only for Python 2, thanks veedrac for pointing this out. Also, here is a benchmark.)Data not in the right order
Each neurotransmitter is roughtly the same but the information about it is spread in multiple dictionnary. It could be worth accessing the element in the other order (so that for instance, for "dopamine", you get all the information in a same place).
Your code now looks like :
```
class Transmitter:
def __init__(self, name):
self.name = name
self.thresholds = [0, 25, 75, 100]
self.level = 1
self.count = 1
def __adjust_threshold(self, subj):
if self.count > 3:
if self.level is "low":
print(subj + "'s " + self.name + " levels have been " + self.level + " lately, resulting in decreased sensitivity.")
self.thresholds[1] += 1
if self.thresholds[1] + 1 >= self.thresholds[2]:
self.thresholds[2] += 1
elif self.level is "high":
print(subj + "'s " + self.name + " levels have been " + self.level + " lately, resulting in increased sensitivity.")
self.thresholds[2] += - 1
if self.thresholds[2] + 1 5:
if (self.level is "normal" and
self.thresholds[2] self.thresholds[0] + 1):
print(subj + "'s " + self.name + " levels have been " + self.level + " lately, resulting in increased resilience.")
self.thresholds[2] += 1
self.thresholds[1] += -1
def adjust_levels(self, level, subj):
if self.thresholds[0] <= level < self.thresholds[1]:
self.__add_count("low")
self.level = "low"
self.__adjust_threshold(subj)
elif self.thresholds[1] <= level < self.thresholds[2]:
self.__add_count("normal")
self.level = "normal"
self.__adjust_threshold(subj)
elif self.thresholds[2] <= level < self.thresholds[3]:
self.__add_count("high")
self.level = "high"
self.__adjust_threshold(subj)
else:
return False
return True
def __add_count(self, level):
Code Snippets
def __determine_emotion(self):
"""
This needs emotions for when one or more neurotransmitters are within
normal ranges.
"""
emo_dict = {
("high", "high", "high"): "INTEREST/EXCITEMENT",
("high", "high", "low") : "ANGER/RAGE",
("high", "low", "high"): "ENJOYMENT/JOY",
("low", "high", "high"): "SURPRISE",
("low", "high", "low") : "CONTEMPT/DISGUST",
("low", "low", "high"): "DISTRESS/ANGUISH",
("low", "low", "low") : "SHAME/HUMILIATION",
}
levels = (self.level["dopamine"], self.level["noradrenaline"], self.level["serotonin"])
self.emotion = emo_dict.get(levels, "NEUTRAL")self.thresholds = {
"dopamine": [0, 25, 75, 100],
"noradrenaline": [0, 25, 75, 100],
"serotonin": [0, 25, 75, 100],
}
self.level = {
"dopamine": "normal",
"noradrenaline": "normal",
"serotonin": "normal",
}
self.count = {
"dopamine": 1,
"noradrenaline": 1,
"serotonin": 1,
}class Transmitter:
def __init__(self, name):
self.name = name
self.thresholds = [0, 25, 75, 100]
self.level = 1
self.count = 1
def __adjust_threshold(self, subj):
if self.count > 3:
if self.level is "low":
print(subj + "'s " + self.name + " levels have been " + self.level + " lately, resulting in decreased sensitivity.")
self.thresholds[1] += 1
if self.thresholds[1] + 1 >= self.thresholds[2]:
self.thresholds[2] += 1
elif self.level is "high":
print(subj + "'s " + self.name + " levels have been " + self.level + " lately, resulting in increased sensitivity.")
self.thresholds[2] += - 1
if self.thresholds[2] + 1 <= self.thresholds[1]:
self.thresholds[1] += - 1
if self.count > 5:
if (self.level is "normal" and
self.thresholds[2] < self.thresholds[3] - 1 and
self.thresholds[1] > self.thresholds[0] + 1):
print(subj + "'s " + self.name + " levels have been " + self.level + " lately, resulting in increased resilience.")
self.thresholds[2] += 1
self.thresholds[1] += -1
def adjust_levels(self, level, subj):
if self.thresholds[0] <= level < self.thresholds[1]:
self.__add_count("low")
self.level = "low"
self.__adjust_threshold(subj)
elif self.thresholds[1] <= level < self.thresholds[2]:
self.__add_count("normal")
self.level = "normal"
self.__adjust_threshold(subj)
elif self.thresholds[2] <= level < self.thresholds[3]:
self.__add_count("high")
self.level = "high"
self.__adjust_threshold(subj)
else:
return False
return True
def __add_count(self, level):
"""
Counts the number of times a subject has been recorded at a given
neurotransmitter level.
"""
if self.level == level:
self.count += 1
else:
self.count = 1
class Emoter:
"""
Create an instance of the class with a name.
Use set_levels to set neurotransmitter levels for dopamine, serotonin, and noradrenaline.
Check current emotion with emotion attribute.
"""
def __init__(self, name):
self.name = name
self.is_alive = True
self.transmitters = {t: Transmitter(t) for t in ('dopamine', 'noradrenaline', 'serotonin')}
self.emotion = "NEUTRAL"
def set_levels(self, values):
"""
Set neurotransmitter levels. Different levels result in different
emotions. Consistently high or low levels can lead to increased or
decreased sensitivity to the neurotransmitter.
"""
for key, val in values.iteritems():
if self.is_alive and not self.transmitters[key].adjust_levels(val,Context
StackExchange Code Review Q#75175, answer score: 6
Revisions (0)
No revisions yet.