- question: "What is your name?"
type: text
required: true
- question: "How old are you?"
type: number
required: true
min_value: 18
max_value: 100
- question: "What is your gender?"
type: multiple_choice
choices:
- Male
- Female
- Other
required: true
- question: "Do you have any dietary restrictions?"
type: checkboxes
choices:
- Vegetarian
- Vegan
- Gluten-free
- Dairy-free
- None
- question: "Which programming languages do you know?"
type: checkboxes
choices:
- Python
- JavaScript
- Java
- C++
- Ruby
- question: "How satisfied are you with our product?"
type: scale
min_value: 1
max_value: 5
- question: "Any additional comments or feedback?"
type: textarea
这上面的YAML是一个非常小的问卷版本,它涉及到近70+个问题.我想设计一个可以读取上述YAML的类,并使其具有动态可伸缩性和可读性. 该类还必须处理数据输入验证,并且必须为阅读它的任何人提供足够的信息. 我怎么能这样做呢?
编辑:
from enum import Enum
import yaml
class QuestionKind(Enum):
TEXT = "text"
NUMBER = "number"
MULTIPLE_CHOICE = "multiple_choice"
CHECKBOXES = "checkboxes"
SCALE = "scale"
TEXTAREA = "textarea"
class Question:
def __init__(self, prompt, kind, choices=None):
self.prompt = prompt
self.kind = kind
self.choices = choices
class Quiz:
def __init__(self, questions_file):
self.questions = self.load_questions(questions_file)
self.current_index = 0
def load_questions(self, questions_file):
with open(questions_file, "r") as file:
data = yaml.safe_load(file)
questions = []
for item in data:
prompt = item["question"]
kind = QuestionKind(item["type"])
choices = item.get("choices")
question = Question(prompt, kind, choices)
questions.append(question)
return questions
def current_question(self):
if self.current_index < len(self.questions):
return self.questions[self.current_index]
else:
return None
def provide_answer(self, answer):
self.current_index += 1
# Process the answer as needed
return self.current_question()
# Usage example
quiz = Quiz("questions.yaml")
current_question = quiz.current_question()
while current_question is not None:
print("Question:", current_question.prompt)
answer = input("Your answer: ")
current_question = quiz.provide_answer(answer)
我正在考虑做这样的事情--这是正确的方式吗?
编辑:这会是改进的方法吗?
import sys
from pathlib import Path
import ruamel.yaml
file_in = Path('questions.yaml')
print(file_in.read_text(), end='===============\n')
class BaseQuestion:
def __init__(self, question, required=False, conditions=None):
self._question = question
self._required = required
self._value = None # to store user response to question
self._conditions = conditions or []
@classmethod
def from_yaml(cls, constructor, node):
kw = ruamel.yaml.CommentedMap()
constructor.construct_mapping(node, kw)
return cls(**kw)
def check_conditions(self, responses):
for condition in self._conditions:
question_id = condition.get('id')
operator = condition.get('operator')
value = condition.get('value')
if question_id in responses and self._compare_values(responses[question_id], operator, value):
return False
return True
def _compare_values(self, value1, operator, value2):
"""Compare two values based on the given operator"""
if operator == "==":
return value1 == value2
elif operator == "!=":
return value1 != value2
elif operator == ">":
return value1 > value2
elif operator == "<":
return value1 < value2
elif operator == ">=":
return value1 >= value2
elif operator == "<=":
return value1 <= value2
else:
raise ValueError(f"Invalid operator: {operator}")
def __repr__(self):
return f'{self.yaml_tag}("{self._question}", required={self._required}, conditions={self._conditions})'
class BaseTextQuestion(BaseQuestion):
yaml_tag = '!Text'
def __init__(self, question, required=False, conditions=None):
super().__init__(question=question, required=required, conditions=conditions)
class TextQuestion(BaseTextQuestion):
yaml_tag = '!Text'
class TextAreaQuestion(BaseTextQuestion):
yaml_tag = '!TextArea'
class NumberQuestion(BaseQuestion):
yaml_tag = '!Number'
def __init__(self, question, min_value, max_value, required=False, conditions=None):
super().__init__(question=question, required=required, conditions=conditions)
self._min = min_value
self._max = max_value
def check(self, responses):
if not self.check_conditions(responses):
return False
if self._required and self._value is None:
return False
if self._value is None:
return True
return self._min <= self._value <= self._max
def __repr__(self):
return f'{self.yaml_tag}("{self._question}", range=[{self._min}, {self._max}], required={self._required}, conditions={self._conditions})'
class ScaleQuestion(NumberQuestion):
yaml_tag = '!Scale'
class ChoiceQuestion(BaseQuestion):
def __init__(self, question, choices, required=False, conditions=None):
super().__init__(question=question, required=required, conditions=conditions)
self._choices = choices
def __repr__(self):
return f'{self.yaml_tag}("{self._question}", choices=[{", ".join(self._choices)}], required={self._required}, conditions={self._conditions})'
class MultipleChoiceQuestion(ChoiceQuestion):
yaml_tag = '!MultipleChoice'
class CheckBoxesQuestion(ChoiceQuestion):
yaml_tag = '!CheckBoxes'
yaml = ruamel.yaml.YAML()
yaml.register_class(TextQuestion)
yaml.register_class(TextAreaQuestion)
yaml.register_class(NumberQuestion)
yaml.register_class(ScaleQuestion)
yaml.register_class(MultipleChoiceQuestion)
yaml.register_class(CheckBoxesQuestion)
questions = yaml.load(file_in)
def display_questions(questions):
"""Display the questions based on the conditions and user responses"""
responses = {}
for question in questions:
if question.check_conditions(responses):
response = input(question._question + " ")
responses[question.__dict__.get("_id")] = response
print("User Responses:", responses)
display_questions(questions)