为什么 IntelliSense 不能与 pandas pipe() 一起使用?
Why won't IntelliSense work with pandas pipe()?
在 VScode 中,Intellisense 似乎无法推断出对 pandas.DataFrame.pipe
的 return 调用类型。这是一些不便的根源,因为我在使用管道后不能依赖自动完成。但是我没有在任何地方看到这个问题,所以这让我想知道是不是只有我一个人,或者我是否遗漏了什么。
我就是这样做的:
import pandas as pd
df = pd.DataFrame({'A': [1,2,3]})
df2 = df.pipe(lambda x: x + 1)
VSCode 将 df
识别为 DataFrame:, but has no clue what df2
might be:
第一个想法是,这是由于 lambda 函数中缺少类型提示。但是,如果我尝试这样做:
def add_one(df: pd.DataFrame) -> pd.DataFrame:
return df + 1
df3 = df.pipe(add_one)
IntelliSense 仍然无法猜测 df3
的类型:
当然,作为最后的手段,我可以给 df3
本身添加一个提示:
df3: pd.DataFrame = df.pipe(add_one)
但似乎没有必要。 IntelliSense 似乎非常有能力推断其他复杂场景中的 return 类型,例如涉及 map
:
更新:
我进行了更多试验,发现了一些有趣的模式,这些模式缩小了可能原因的范围。
我对 Pylance 不够熟悉,无法真正理解为什么会发生这种情况,但这是我的发现:
发现 1
如果导入 pandas.core.common.pipe 就会发生这种情况。 (我知道 pd.DataFrame.pipe 调用 pandas.core.generic.pipe,但内部调用 pandas.core.common.pipe,我可以在 pandas.core.common.pipe 中重现该问题。)
发现 2
如果我从 pandas.core.common 复制相同函数的定义,连同 Callable 和 TypeVar 的相关导入,并将 T
声明为 TypeVar('T')
,IntelliSense 实际上会发挥它的魔力.
(实际上在pandas.core.common中,T
没有被定义为TypeVar('T')
,而是从pandas._typing中导入的,它被定义为TypeVar('T')
。如果我导入它而不是自己定义它,它仍然可以正常工作。)
据此我很想得出结论 pandas 做的一切都是正确的,但是 Pylance 出于某种未知原因未能跟踪类型信息...
发现 3
如果我只是将 pandas.core.common 复制到本地文件 pandascommon.py 并从中导入管道,它也可以正常工作!
我也在vscode中模拟了一下,发现确实存在这个问题。我想可能和pipe()方法中的return值定义有关。我在GitHub上提交了问题,希望有所收获。
我明白了!
这是由于 Pylance 附带的存根。具体在 ~/.vscode/extensions/ms-python.vscode-pylance-2022.3.2/dist/bundled/stubs/pandas/
.
例如在 core/common.pyi 中我发现了这个存根:
def pipe(obj, func, *args, **kwargs): ...
Pylance 使用这个而不是 pandas.core.common.pipe
中的注释,导致了这个问题。
一个 heavy-handed 解决方案是删除(或重命名)该文件夹中的 pandas 存根。然后管道再次工作。另一方面,它破坏了其他一些东西,例如 read_csv 不再被正确推断为 return 一个 DataFrame。我认为更好的长 运行 解决方案是让 Pylance 维护者改进这些存根...
原始 pipe
问题的微创解决方案是按以下方式编辑 ~/.vscode/extensions/ms-python.vscode-pylance-2022.3.2/dist/bundled/stubs/pandas/core/frame.pyi
:
添加from pandas._typing import T
将以def pipe
开头的行替换为:
def pipe(self, func: Callable[..., T], *args, **kwargs) -> T: ...
在 VScode 中,Intellisense 似乎无法推断出对 pandas.DataFrame.pipe
的 return 调用类型。这是一些不便的根源,因为我在使用管道后不能依赖自动完成。但是我没有在任何地方看到这个问题,所以这让我想知道是不是只有我一个人,或者我是否遗漏了什么。
我就是这样做的:
import pandas as pd
df = pd.DataFrame({'A': [1,2,3]})
df2 = df.pipe(lambda x: x + 1)
VSCode 将 df
识别为 DataFrame:df2
might be:
第一个想法是,这是由于 lambda 函数中缺少类型提示。但是,如果我尝试这样做:
def add_one(df: pd.DataFrame) -> pd.DataFrame:
return df + 1
df3 = df.pipe(add_one)
IntelliSense 仍然无法猜测 df3
的类型:
当然,作为最后的手段,我可以给 df3
本身添加一个提示:
df3: pd.DataFrame = df.pipe(add_one)
但似乎没有必要。 IntelliSense 似乎非常有能力推断其他复杂场景中的 return 类型,例如涉及 map
:
更新:
我进行了更多试验,发现了一些有趣的模式,这些模式缩小了可能原因的范围。
我对 Pylance 不够熟悉,无法真正理解为什么会发生这种情况,但这是我的发现:
发现 1
如果导入 pandas.core.common.pipe 就会发生这种情况。 (我知道 pd.DataFrame.pipe 调用 pandas.core.generic.pipe,但内部调用 pandas.core.common.pipe,我可以在 pandas.core.common.pipe 中重现该问题。)
发现 2
如果我从 pandas.core.common 复制相同函数的定义,连同 Callable 和 TypeVar 的相关导入,并将 T
声明为 TypeVar('T')
,IntelliSense 实际上会发挥它的魔力.
(实际上在pandas.core.common中,T
没有被定义为TypeVar('T')
,而是从pandas._typing中导入的,它被定义为TypeVar('T')
。如果我导入它而不是自己定义它,它仍然可以正常工作。)
据此我很想得出结论 pandas 做的一切都是正确的,但是 Pylance 出于某种未知原因未能跟踪类型信息...
发现 3
如果我只是将 pandas.core.common 复制到本地文件 pandascommon.py 并从中导入管道,它也可以正常工作!
我也在vscode中模拟了一下,发现确实存在这个问题。我想可能和pipe()方法中的return值定义有关。我在GitHub上提交了问题,希望有所收获。
我明白了!
这是由于 Pylance 附带的存根。具体在 ~/.vscode/extensions/ms-python.vscode-pylance-2022.3.2/dist/bundled/stubs/pandas/
.
例如在 core/common.pyi 中我发现了这个存根:
def pipe(obj, func, *args, **kwargs): ...
Pylance 使用这个而不是 pandas.core.common.pipe
中的注释,导致了这个问题。
一个 heavy-handed 解决方案是删除(或重命名)该文件夹中的 pandas 存根。然后管道再次工作。另一方面,它破坏了其他一些东西,例如 read_csv 不再被正确推断为 return 一个 DataFrame。我认为更好的长 运行 解决方案是让 Pylance 维护者改进这些存根...
原始 pipe
问题的微创解决方案是按以下方式编辑 ~/.vscode/extensions/ms-python.vscode-pylance-2022.3.2/dist/bundled/stubs/pandas/core/frame.pyi
:
添加
from pandas._typing import T
将以
def pipe
开头的行替换为:def pipe(self, func: Callable[..., T], *args, **kwargs) -> T: ...