multigoodverse
multigoodverse

Reputation: 8072

How to efficiently evaluate a series of methods and call the ones that are not False?

The class below gets a string as input and produces another string via the answer() method.

class Question:

    a = ["hello", "hi"]
    b = ["how are you", "how do you do"]
    c = ["how is the weather", "is it cold today"]

    def __init__(self, question):
        self.question = question

    def get_greeting(self):
        if self.question in Question.a:
            return "Hi There!"

    def get_health(self):
        if self.question in Question.b:
            return "I am fine"

    def get_weather(self):
        if self.question in Question.c:
            return "It is warm"

    def answer(self):

        if self.get_greeting():
            return self.get_greeting()
        elif self.get_health():
            return self.get_health()
        elif self.get_weather():
            return self.get_weather()
        else:
            return "I don't understand"

question = Question("how is the weather") 
print(question.answer()) # getting the output

To me the above is bad because the code inside answer() it's long and it calls each method twice.

Therefore, I came up with a "better" answer() method that calls the methods only once, but it's still a lot of if conditionals.

def answer(self):

    result = self.get_greeting()
    if result:
        return result

    result = self.get_health()
    if result:
        return result

    result = self.get_weather()
    if result:
        return result

    return "I don't understand"

I think there might be some other technique that I am missing here. Anyone can suggest something?

Upvotes: 0

Views: 35

Answers (2)

Felix
Felix

Reputation: 6359

You can make a tuple of all methods and then call them until one returns something:

def answer(self):
    methods = (self.get_greeting, self.get_health, self.get_weather)
    for m in methods:
        res = m()
        if res:
            return res
    return "I don't understand"

Edit

If you really want to create a lot of methods and have your answer() function try them all without explicitly telling it, you can use this code:

def answer(self):
        getters = (v for k, v in self.__class__.__dict__.items() if k.startswith("get_"))
        for method in getters:
            res = method(self)
            if res:
                return res
        return "I don't understand"

Edit 2

If your system just gets a string as an input and generates predefined outputs from it, you may be able to simplify it quite a bit:

knowledge = [
    (["hello", "hi"], "Hi There"),
    (["how are you", "how do you do"], "I am fine"),
    (["how is the weather", "is it cold today"], "It is warm")
]

def answer(question):
    for inputs, answer in knowledge:
        if question in inputs:
            return answer
    return "I don't understand"

print(answer("hello"))

Using this approach, adding a new phrase to the chatbot is as easy as adding a line to the knowledge data structure.

Upvotes: 2

molbdnilo
molbdnilo

Reputation: 66441

The result of or is the left-hand operand if it's not "false-y", otherwise the right-hand operand.
It also evaluates the right-hand operand only when it's needed.

def answer(self):
    return self.get_greeting() \
        or self.get_health() \
        or self.get_weather() \
        or "I don't understand"

Upvotes: 3

Related Questions