PyCharm: "функция ничего не возвращает"

я только начал работать с PyCharm Community Edition 2016.3.2 сегодня. Каждый раз, когда я присвоить значение функции at_square, Он предупреждает меня, что 'функция at_square ничего не возвращает, но это определенно происходит в каждом случае, если во время выполнения не возникает ошибка, и каждое использование функции ведет себя так, как ожидалось. Я хочу знать, почему Пайчарм думает, что это не так, и могу ли я что-нибудь сделать, чтобы исправить это. (Я знаю, что есть возможность подавить предупреждение для этого конкретная функция, но она делает это, вставляя прокомментированную строку в мой код выше функции, и я нахожу это так же раздражающим, чтобы помнить, чтобы вынуть это в конце проекта.)

это функция, о которой идет речь:

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]

если это имеет значение, это более точно метод объекта. Я застрял с функцией термин, потому что это язык PyCharm использует.

моя единственная мысль заключается в том, что мое использование ошибки может быть путаешь PyCharm, но это кажется слишком простым. (Пожалуйста, не стесняйтесь критиковать мою ошибку, так как я не уверен, что это идиоматический способ сделать это.)

обновление: С юмором, если я полностью удаляю обратную линию, предупреждение уходит и возвращается немедленно, когда я кладу его обратно. Он также уходит, если я заменяю self.board[file][rank] С постоянным значением, как 8. Меняется file или rank для постоянных значений не удаляет предупреждение, поэтому я понимаю, что 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 дает такое же предупреждение. Если я только уйду ... обратная линия, тогда и только тогда предупреждение исчезает. Кажется, что PyCharm смущен одновременным назначением file и rank via 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

обновление: в своем конструкторе класс Board (который является родительским классом для всех этих методов) сохраняет ссылку на этот экземпляр в статической переменной instance. self.at_square(square) дает предупреждение, в то время как Board.instance.at_square(square) нет. Я все еще собираюсь использовать бывший, когда это уместно, но это может пролить свет на то, что думает PyCharm.

1 ответов


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

в этот момент Foo.bar is статически выводится как (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