HiveBrain v1.2.0
Get Started
← Back to all entries
patternpythonMinor

Reflecting emotion classification based on the Lövheim cube

Submitted by: @import:stackexchange-codereview··
0
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 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 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 need

Using 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.