有一段代码可以在循环中构建问题对象,并且每个问题都可以选择构建possibleAnswers对象。
问题类别是:
class Question(graphene.ObjectType): # type: ignore
qId = graphene.String()
label = graphene.String()
question = graphene.String()
multipleAnswersAccepted = graphene.Boolean()
possibleAnswers = graphene.List(PossibleAnswer)
def __init__(self, questionObj: QuestionMeta) -> None:
print("__ questionObj type={y}".format(y=type(questionObj)))
self.qId = questionObj.qPointer
self.label = questionObj.label
self.question = questionObj.question
self.inputType = questionObj.inputType
self.multipleAnswersAccepted = questionObj.multipleAnswersAccepted
if questionObj.possibleAnswersPointer:
self.possibleAnswers = []
for _key, value in enumerate(questionObj.possibleAnswersPointer):
print("___possibleAnswersPointer is {}".format(
type(value)))
# x = PossibleAnswerMeta(**value)
possibleAnswer = PossibleAnswer(paObj=PossibleAnswerMeta(**value))
self.addPossibleAnswer(possibleAnswer)
else:
self.possibleAnswers = None
def addPossibleAnswer(self, possibleAnswer: Dict[int, str]) -> None:
"""Append possible-answer object to array of possible answers."""
self.possibleAnswers.append(possibleAnswer)
可能的答案是
class PossibleAnswer(graphene.ObjectType): # type: ignore
paId = graphene.String()
text = graphene.String()
def __init__(self, paObj: PossibleAnswerMeta) -> None:
print("__ paObj type={y}".format(y=type(paObj)))
self.paId = paObj.paId
self.text = paObj.text
并且创建者中的两个类都使用定义为QuestionMeta
或PossibleAnswerMeta
的类型的对象,这些对象在classes
模块中定义:
class PossibleAnswerMeta(NamedTuple):
text: str
paId: int
score: int
class QuestionMeta(NamedTuple):
qPointer: str
label: str
question: str
multipleAnswersAccepted: bool
possibleAnswersPointer: List[PossibleAnswerMeta]
创建问题的循环是:
for _questionNum, questionData in enumerate(value):
print("___questionData type is {}".format(type(questionData)))
q = Question(questionObj=QuestionMeta(**questionData))
s.addQuestion(question=q)
所以我们可以看到问题得到questionObj=QuestionMeta(**questionData)
作为参数,而possibleAnswer得到paObj=PossibleAnswerMeta(**value)
。
两者都是基于NamedTuple的类型,questionData
和value
都有相同类型的<class 'dict'>
,但mypy只抱怨价值。
当我运行mypy时,我得到以下输出:
..79: error: Argument after ** must be a mapping
,第79行是possibleAnswer = PossibleAnswer(paObj=PossibleAnswerMeta(**value))
线。
问题:代码运行正常,两个对象都正确创建(我看到它们在石墨烯查询中返回),参数类型相同,在日志中打印
那么为什么mypy只抱怨传递价值,而不是关于questionData,因为两者都是od'dict'类型?
...
__ questionObj type=<class 'user.api.meta.classes.QuestionMeta'>
___possibleAnswersPointer is <class 'dict'>
__ paObj type=<class 'user.api.meta.classes.PossibleAnswerMeta'>
___possibleAnswersPointer is <class 'dict'>
__ paObj type=<class 'user.api.meta.classes.PossibleAnswerMeta'>
___possibleAnswersPointer is <class 'dict'>
__ paObj type=<class 'user.api.meta.classes.PossibleAnswerMeta'>
___questionData type is <class 'dict'>
__ questionObj type=<class 'user.api.meta.classes.QuestionMeta'>
___possibleAnswersPointer is <class 'dict'>
__ paObj type=<class 'user.api.meta.classes.PossibleAnswerMeta'>
___possibleAnswersPointer is <class 'dict'>
__ paObj type=<class 'user.api.meta.classes.PossibleAnswerMeta'>
您的类型确实存在问题,mypy正在警告您。
让我们看一下输出中的所有那些行
___possibleAnswersPointer is <class 'dict'>
首先,那不是possibleAnswersPointer
。你正在打印一个误导性的消息;这是possibleAnswersPointer
元素的类。
其次,possibleAnswersPointer
的元素不应该是dicts。你告诉mypy他们完全是别的东西:
possibleAnswersPointer: List[PossibleAnswerMeta]
你告诉mypy,possibleAnswersPointer
的元素将是PossibleAnswerMeta
的实例。 mypy是绝对正确的,警告你PossibleAnswerMeta
的实例不是映射,不能用**
解压缩。您没有收到运行时错误,因为possibleAnswersPointer
的元素不是您告诉mypy它们的内容。
如果possibleAnswersPointer
的元素不应该是PossibleAnswerMeta
的实例,那么不要告诉mypy它们将是该类的实例。如果possibleAnswersPointer
的元素应该是PossibleAnswerMeta
的实例,那么你有mypy警告你的bug,以及任何导致这些元素的错误。