PyCharm:'功能不会归还任何东西'

Ram*_*nev 9 pycharm python-3.x

我今天刚开始使用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]
Run Code Online (Sandbox Code Playgroud)

如果重要,这更确切地说是一个对象的方法.我坚持使用术语'函数',因为这是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])
Run Code Online (Sandbox Code Playgroud)

PyCharm没有给出任何警告.在at_square,我已经尝试将每一行评论为以下两行:

def at_square(self, square):
    file, rank = Board.tup_from_an(square)
    return self.board[file][rank]
Run Code Online (Sandbox Code Playgroud)

PyCharm给出了同样的警告.如果我只留下返回线,那么只有那时警告才会消失.PyCharm似乎被同时分配filerank通过混淆tup_from_an.以下是该方法的代码:

@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
Run Code Online (Sandbox Code Playgroud)

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

Mis*_*agi 5

如果返回值静态求值为,则PyCharm假定缺少返回值None.如果使用初始化值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
Run Code Online (Sandbox Code Playgroud)

在这一点上,Foo.bar静态推断为(self: Foo) -> None.动态更改quxvia副作用的类型不会更新:

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
Run Code Online (Sandbox Code Playgroud)

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

您可以使用显式类型提示来解决此问题.

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
Run Code Online (Sandbox Code Playgroud)

从Python 3.5开始,您还可以使用内联类型提示.这些对返回类型特别有用.

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
Run Code Online (Sandbox Code Playgroud)

请注意,依赖推理它仍然是一个好主意!注释只会self.qux使以后更容易更改类型.注释bar主要用于文档和覆盖不正确的推理.

如果需要支持3.5之前的版本,还可以使用存根文件.假设您的班级在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:
        ...
Run Code Online (Sandbox Code Playgroud)