**之后的mypy参数必须是映射

问题描述 投票:0回答:1

有一段代码可以在循环中构建问题对象,并且每个问题都可以选择构建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

并且创建者中的两个类都使用定义为QuestionMetaPossibleAnswerMeta的类型的对象,这些对象在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的类型,questionDatavalue都有相同类型的<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'>
python python-3.x mypy
1个回答
1
投票

您的类型确实存在问题,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,以及任何导致这些元素的错误。

© www.soinside.com 2019 - 2024. All rights reserved.