我刚刚开始使用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
,它也会消失。将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给出了同样的警告。如果我只留下返回线,那么只有那时警告才会消失。通过file
同时分配rank
和tup_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的想法。
答案 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)
现在推荐以下示例中的样式:
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也在不断改进。这些相对不成熟的高级功能的快速开发需要付出代价,这意味着下一个电话可能是检查还是提交给问题跟踪器。