PyCharm:'功能不会返回任何内容'

时间:2017-02-09 02:58:19

标签: python-3.x pycharm

我刚刚开始使用PyCharm Community Edition 2016.3.2。每次我从我的函数at_square中分配一个值时,它都会警告我'函数at_square没有返回任何内容,'但它绝对会在每个实例中执行,除非在执行期间引发错误,并且函数的每次使用都按预期运行。我想知道为什么PyCharm认为它没有,以及我能做些什么来纠正它。 (我知道有一个选项可以禁止该特定函数的警告,但是它通过在函数上方的代码中插入一条注释行来实现,并且我觉得必须记住最后将它取出来也很烦人该项目。)

这是有问题的功能:

def at_square(self, square):
    """ Return the value at the given square """
    if type(square) == str:
        file, rank = Board.tup_from_an(square)
    elif type(square) == tuple:
        file, rank = square
    else:
        raise ValueError("Expected tuple or AN str, got " + str(type(square)))

    if not 0 <= file <= 7:
        raise ValueError("File out of range: " + str(file))
    if not 0 <= rank <= 7:
        raise ValueError("Rank out of range: " + str(rank))

    return self.board[file][rank]

如果重要,这更确切地说是一种物体的方法。我坚持使用术语&#39;功能&#39;因为那是PyCharm正在使用的语言。

我唯一想到的是我使用错误提升可能会让PyCharm感到困惑,但这似乎太简单了。 (请随意批评我的错误提升,因为我不确定这是否是惯用的方式。)

更新:幽默地说,如果我完全删除了返回行,警告会消失并在我放回时立即返回。如果我用self.board[file][rank]之类的常量值替换8,它也会消失。将filerank更改为常量值不会删除警告,因此我认为PyCharm在某种程度上混淆了self.board的性质,这是其他8个列表的列表。

更新:根据@StephenRauch的建议,我创建了一个最小的示例,反映了与at_square完成的数据分配相关的所有内容:

class Obj:
    def __init__(self):
        self.nested_list = [[0],[1]]

    @staticmethod
    def tup_method(data):
        return tuple(data)

    def method(self,data):
        x,y = Obj.tup_method(data)
        return self.nested_list[x][y]

    def other_method(self,data):
        value = self.method(data)
        print(value)

x = Obj()
x.other_method([1,2])

PyCharm没有对此发出任何警告。在at_square中,我尝试将每一行评论为以下两行:

def at_square(self, square):
    file, rank = Board.tup_from_an(square)
    return self.board[file][rank]

PyCharm给出了同样的警告。如果我只留下返回线,那么只有那时警告才会消失。通过file同时分配ranktup_from_an,PyCharm似乎感到困惑。以下是该方法的代码:

@staticmethod
def tup_from_an(an):
    """ Convert a square in algebraic notation into a coordinate tuple """
    if an[0] in Board.a_file_dict:
        file = Board.a_file_dict[an[0]]
    else:
        raise ValueError("Invalid an syntax (file out of range a-h): " + str(an))

    if not an[1].isnumeric():
        raise ValueError("Invalid an syntax (rank out of range 1-8): " + str(an))
    elif int(an[1]) - 1 in Board.n_file_dict:
        rank = int(an[1]) - 1
    else:
        raise ValueError("Invalid an syntax (rank out of range 1-8): " + str(an))

    return file, rank

更新:在其构造函数中,类Board(所有这些方法的父类)在静态变量instance中保存对实例的引用。 self.at_square(square)会发出警告,而Board.instance.at_square(square)却没有。我仍然会在适当的时候使用前者,但这可以解释PyCharm的想法。

2 个答案:

答案 0 :(得分:5)

如果返回值静态评估为None,则PyCharm会假定缺少返回值。如果使用None初始化值并稍后更改其类型,则会发生这种情况。

class Foo:
    def __init__(self):
        self.qux = [None]  # infers type for Foo().qux as List[None]

    def bar(self):
        return self.qux[0]  # infers return type as None

此时,Foo.bar 静态推断为(self: Foo) -> None动态通过副作用更改qux的类型不会更新此内容:

foo = Foo()
foo.qux = [2]  # *dynamic* type of foo.bar() is now ``(self: Foo) -> int``
foo_bar = foo.bar()  # Function 'bar' still has same *static* type

问题是您是通过动态分配的实例属性覆盖静态推断的类属性。对于静态分析来说,这通常是不可行的。

您可以使用显式类型提示修复此问题。

import typing


class Foo:
    def __init__(self):
        self.qux = [None]  # type: typing.List[int]

    def bar(self):
        return self.qux[0]  # infers return type as int

自Python 3.5起,您还可以使用inline type hints。这些对返回类型特别有用。

import typing


class Foo:
    def __init__(self):
        # initial type hint to enable inference
        self.qux: typing.List[int] = [None]

    # explicit return type hint to override inference
    def bar(self) -> int:
        return self.qux[0]  # infers return type as int

请注意,依赖推理它仍然是一个好主意!仅注释self.qux可以在以后更轻松地更改类型。注释bar主要用于文档和覆盖不正确的推理。

如果您需要支持3.5之前的版本,还可以使用stub files。假设您的班级位于foomodule.py,请创建一个名为foomodule.pyi的文件。在里面,只需添加带注释的字段和功能签名;你可以(并且应该)遗漏尸体。

import typing


class Foo:
    # type hint for fields
    qux: typing.List[int]

    # explicit return type hint to override inference
    def bar(self) -> int:
        ...

答案 1 :(得分:2)

从Python 3.6开始的类型提示

现在推荐以下示例中的样式:

from typing import typing

class Board:
    def __init__(self):
        self.board: List[List[int]] = []

快速文档

Pycharm的“快速文档”显示是否正确输入。将光标放在感兴趣的对象的中间,然后按Ctrl + Q。我怀疑来自tup_from_an(an)的类型将不是所期望的。您可以尝试键入提示所有的args和内部对象,但最好仅键入函数返回类型作为提示。类型提示意味着我不需要遍历外部文档,因此我将精力集中在将由外部用户使用的对象上,并尽量不要做太多内部工作。这是arg和返回类型提示:

@staticmethod
    def tup_from_an(an: List[int]) -> (int, int):
        ...

清除缓存

Pycharm可以锁定过期的定义。不必忙于帮助>查找操作...>清除缓存

没有完美的身体

Python一直在改进(类型提示已在3.7中更新)Pycharm也在不断改进。这些相对不成熟的高级功能的快速开发需要付出代价,这意味着下一个电话可能是检查还是提交给问题跟踪器。