python-3.x - 绑定(bind)方法的 MyPy 类型注释?

标签 python-3.x mypy

我正在使用 pytest 为库编写一些测试.我想为库公开的每个函数尝试一些测试用例,所以我发现将每个方法的测试分组到一个类中很方便。我要测试的所有函数都具有相同的签名并返回相似的结果,因此我想使用父类(super class)中定义的辅助方法对结果进行一些断言。简化版本会像这样运行:

class MyTestCase:
    function_under_test: Optional[Callable[[str], Any]] = None

    def assert_something(self, input_str: str, expected_result: Any) -> None:
        if self.function_under_test is None:
            raise AssertionError(
                "To use this helper method, you must set the function_under_test"
                "class variable within your test class to the function to be called.")

        result = self.function_under_test.__func__(input_str)
        assert result == expected_result
        # various other assertions on result...


class FunctionATest(MyTestCase):
    function_under_test = mymodule.myfunction

    def test_whatever(self):
        self.assert_something("foo bar baz")

assert_something ,有需要的请拨打__func__()在函数上,因为将函数分配给类属性使其成为该类的绑定(bind)方法 - 否则 self将作为第一个参数传递给外部库函数,在那里它没有任何意义。

此代码按预期工作。但是,它会产生 MyPy 错误:
"Callable[[str], Any]" has no attribute "__func__"

根据我的注释,这不是安全操作是正确的:任意 Callable 可能没有 __func__属性。但是,我找不到任何类型注释表明 function_under_test变量指的是一个方法,因此总是有 __func__ .我是否忽略了一个,或者是否有另一种方法来调整我的注释或访问以使其与类型检查一起工作?

当然,我还有很多其他方法可以解决这个问题,其中一些甚至可能更简洁(使用 Any 类型,跳过类型检查,使用私有(private)方法返回被测函数而不是使其成为类变量,使辅助方法成为函数等)。我更感兴趣的是是否有注释或其他 mypy 技巧可以使此代码正常工作。

最佳答案

Callable 仅确保您的对象具有 __call__方法。
你的问题是你的电话self.function_under_test.__func__(input_str)你应该调用你的函数 self.function_under_test(input_str)请参阅下面没有 mypy 投诉的示例(v0.910)

from typing import Any, Callable, Optional


class MyTestCase:
    function_under_test: Optional[Callable] = None

    def myfunction_wrap(self, *args, **kwargs):
        raise NotImplementedError

    def assert_something(self, input_str: str, expected_result: Any) -> None:
        if self.function_under_test is None:
            raise AssertionError(
                "To use this helper method, you must set the function_under_test"
                "class variable within your test class to the function to be called.")

        result = self.myfunction_wrap(input_str)
        assert result == expected_result
        # various other assertions on result...


def myfunction(a: str) -> None:
    ...


class FunctionATest(MyTestCase):
    def myfunction_wrap(self, *args, **kwargs):
        myfunction(*args, **kwargs)

    def test_whatever(self):
        self.assert_something("foo bar baz")

Edit1:错过了问题的重点,在包装函数中移动了函数

关于python-3.x - 绑定(bind)方法的 MyPy 类型注释?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58085648/

相关文章:

Python字典替换值

python-3.x - 属性错误: 'NoneType' object has no attribute '_root' (My case is different)

python - setuptools 如何向运行时添加模块?

c# - 我可以在 Python3 中使用不同的代码点吗?

python - Typehint 使用 importlib 动态导入模块

python - 为什么 mypy 找不到我的包裹?

python-3.x - 使用 PIL 和 SKIMAGE 打开 PGM 文件时出错

通用 *args 的 Python 类型提示(特别是 zip 或 zipWith)

python - mypy 错误 :Incompatible types in assignment (expression has type "List[str]", 变量的类型为 "str")

python - mypy 可以处理列表推导式吗?