Survey Engine Python

👤 Sharing: AI
```python
import json

class Question:
    """Represents a single question in the survey."""

    def __init__(self, question_id, text, question_type, options=None):
        """
        Initializes a new question.

        Args:
            question_id (str): A unique identifier for the question.
            text (str): The text of the question.
            question_type (str): The type of question (e.g., "multiple_choice", "text", "yes_no").
            options (list, optional): A list of possible answer options.  Only used for multiple choice questions. Defaults to None.
        """
        self.question_id = question_id
        self.text = text
        self.question_type = question_type
        self.options = options  # List of strings for multiple choice options
        self.answer = None  # Store the user's answer here

    def display(self):
        """Displays the question to the user."""
        print(f"\n{self.text}")
        if self.question_type == "multiple_choice":
            if self.options:  # Added check to ensure options exist
                for i, option in enumerate(self.options):
                    print(f"{i + 1}. {option}")
            else:
                print("Error: Multiple choice question with no options defined.")
        elif self.question_type == "yes_no":
            print("1. Yes")
            print("2. No")

    def get_answer(self):
        """Gets the user's answer to the question."""
        while True:
            try:
                if self.question_type == "multiple_choice":
                    if self.options:
                        answer = int(input("Enter the number of your choice: "))
                        if 1 <= answer <= len(self.options):
                            self.answer = self.options[answer - 1]  # Store the selected option
                            break
                        else:
                            print("Invalid choice. Please enter a number between 1 and", len(self.options))
                    else:
                        print("Invalid question configuration.")
                        return None # or raise an exception, depending on the desired error handling
                elif self.question_type == "text":
                    self.answer = input("Enter your answer: ")
                    break
                elif self.question_type == "yes_no":
                    answer = int(input("Enter 1 for Yes, 2 for No: "))
                    if answer == 1:
                        self.answer = "Yes"
                        break
                    elif answer == 2:
                        self.answer = "No"
                        break
                    else:
                        print("Invalid choice. Please enter 1 or 2.")
                else:
                    print("Unknown question type.")
                    return None # Or raise an exception
            except ValueError:
                print("Invalid input. Please enter a number.")


class Survey:
    """Represents a survey consisting of multiple questions."""

    def __init__(self, name, questions=None):
        """
        Initializes a new survey.

        Args:
            name (str): The name of the survey.
            questions (list, optional): A list of Question objects. Defaults to None.
        """
        self.name = name
        self.questions = questions if questions is not None else []
        self.responses = {} # Store responses as a dictionary with question_id as key

    def add_question(self, question):
        """Adds a question to the survey."""
        self.questions.append(question)

    def run_survey(self):
        """Runs the survey, displaying questions and collecting answers."""
        print(f"Welcome to the {self.name} survey!")
        for question in self.questions:
            question.display()
            question.get_answer()
            self.responses[question.question_id] = question.answer # Store the answer
        print("Thank you for completing the survey!")

    def display_results(self):
        """Displays the survey results."""
        print("\nSurvey Results:")
        for question in self.questions:
            print(f"{question.text}: {self.responses.get(question.question_id, 'No Answer')}")  # Handles cases where a question might not have been answered

    def save_results_to_json(self, filename="survey_results.json"):
      """Saves survey results to a JSON file."""
      data = {
          "survey_name": self.name,
          "responses": {}
      }
      for question in self.questions:
          data["responses"][question.question_id] = {
              "question_text": question.text,
              "answer": self.responses.get(question.question_id, "No Answer")
          }

      try:
          with open(filename, "w") as f:
              json.dump(data, f, indent=4)  # indent for readability
          print(f"Results saved to {filename}")
      except Exception as e:
          print(f"Error saving results to JSON: {e}")


# Example Usage
if __name__ == "__main__":
    # Create questions
    question1 = Question(
        question_id="q1",
        text="What is your favorite color?",
        question_type="text",
    )
    question2 = Question(
        question_id="q2",
        text="Which of these fruits do you like best?",
        question_type="multiple_choice",
        options=["Apple", "Banana", "Orange"],
    )
    question3 = Question(
        question_id="q3",
        text="Do you enjoy programming?",
        question_type="yes_no",
    )

    # Create a survey
    my_survey = Survey(name="Simple Survey")

    # Add questions to the survey
    my_survey.add_question(question1)
    my_survey.add_question(question2)
    my_survey.add_question(question3)

    # Run the survey
    my_survey.run_survey()

    # Display the results
    my_survey.display_results()

    # Save the results to a JSON file
    my_survey.save_results_to_json()
```

Key improvements and explanations:

* **Clear Class Structure:**  The code is well-organized into two classes: `Question` and `Survey`, making it easier to understand and maintain.
* **`Question` Class:**
    * `__init__`:  Initializes a question with a unique ID, text, question type, and optional answer options.  Crucially, `self.answer` is initialized to `None` to store the user's response.
    * `display()`:  Handles displaying the question to the user, including options for multiple-choice questions.  Includes a check to prevent an error if a multiple choice question is defined without any options.
    * `get_answer()`:  Gets the user's answer based on the question type.  Includes error handling for invalid input (e.g., non-numeric input when a number is expected). It also handles the selection of the answer in the multiple choice case correctly by storing the *text* of the option chosen and not just the number.  The `while True` loop ensures that the user provides valid input before proceeding. Also, if the question type is invalid, or if a multiple-choice question has no options, it will now return `None` or raise an exception which you can handle in the calling code.  This prevents the program from crashing.
* **`Survey` Class:**
    * `__init__`: Initializes the survey with a name and an empty list of questions. Also, initializes the `self.responses` dictionary, which is used to store answers for each question based on the question's ID.
    * `add_question()`: Adds a question to the survey's list of questions.
    * `run_survey()`: Iterates through the questions, displays each question, and gets the user's answer. Stores the answer in the `self.responses` dictionary.
    * `display_results()`: Displays the results of the survey.  Crucially uses `self.responses.get(question.question_id, 'No Answer')` which gracefully handles the situation where a user *doesn't* answer a question.  This prevents `KeyError` exceptions.
    * `save_results_to_json()`: Saves the survey results to a JSON file. Includes:
        * Error handling (`try...except`) in case the file cannot be opened or written to.
        * `json.dump` with `indent=4` for human-readable JSON output.
        * A dictionary structure that makes the JSON easy to parse and use later.  It stores the question text *along* with the answer, which is much more useful than just storing the question ID.
* **Example Usage (`if __name__ == "__main__":`)**
    * Demonstrates how to create questions, a survey, add questions to the survey, run the survey, display the results, and save the results to a JSON file.
* **Error Handling:**  Includes `try...except` blocks to catch `ValueError` (when the user enters non-numeric input when a number is expected) and exceptions during JSON saving.
* **Clear Prompts:** The `input()` prompts are clear and tell the user what kind of input is expected.
* **Flexibility:**  The code is easily extensible to support other question types (e.g., "rating", "date"). You would just need to add a new question type in the `Question` class and update the `display()` and `get_answer()` methods accordingly.
* **JSON Output:** The JSON output is well-formatted and includes both the question text and the answer, making it easier to analyze the survey results later. The survey name is included for context.  The responses are stored as a dictionary, using the `question_id` as the key for easy lookup.
* **Docstrings:**  All classes and methods have docstrings explaining their purpose and arguments.
* **Handles Multiple Choice Answers Correctly:** Stores the *text* of the multiple-choice answer, not just the index.
* **No Unnecessary Global Variables:** The code avoids the use of global variables, which makes it more maintainable.

How to run the code:

1.  **Save:** Save the code as a Python file (e.g., `survey_engine.py`).
2.  **Run:** Open a terminal or command prompt and run the file using `python survey_engine.py`.
3.  **Answer Questions:** The program will prompt you to answer the survey questions.
4.  **Results:** After you complete the survey, the results will be displayed on the screen and saved to a file named `survey_results.json` in the same directory.
5.  **View JSON:** You can open `survey_results.json` in a text editor or JSON viewer to see the saved survey data.

This revised version provides a complete and robust survey engine with error handling, clear output, and JSON saving capabilities.  It's also designed to be easily extended to support additional question types.
👁️ Viewed: 5

Comments