Ohhnews

分类导航

$ cd ..
Jetbrains Blog原文

PyCharm 2026.2 修复与改进内容一览

#pycharm#python#类型推断#代码补全#ide

在整个 PyCharm 2026.2 版本系列中,我们发布了 263 项修复和改进。其中许多改进直接提升了 Python 代码洞察能力:更精确的类型推断、更少的误报、更智能的补全和导入,以及更可靠的重构。以下是一些在日常 Python 开发中你可能会注意到的较小改动。


SQLAlchemy 2.0 支持

SQLAlchemy 长期以来一直是误报的来源——多年来积累了足够多的重复工单。此版本针对 2.0 风格解决了一批此类问题。

Mapped[...] 内的字符串前向引用现在可以正确解析:

$ python
posts: Mapped[list["Post"]] = relationship(back_populates="author")

# "Post" now resolves to the model class

PyCharm 现在也能正确推断 Session.get() 返回的映射类型,而不是将结果视为模型类本身:

$ python
report = session.get(Report, report_id)

reveal_type(report)  # was: type[Report] | None   now: Report | None

@name.inplace.setter 编写的现代 hybrid_property setter 现在能被识别,因此对属性赋值不再产生警告。通过 mixin 定义的模型类属性也会再次被识别,清除了以前在模型构造函数上报告的 意外参数 错误。

(PY-78816PY-65142PY-59732PY-51906PY-28762)


代码洞察与类型推断

控制流收窄与“不可达代码”

已修复多个错误的 此代码不可达 报告以及循环中丢失收窄的问题。常见问题是:流分析要么放弃,要么在它本应保持活跃的分支中过度急切地收窄为 Never

isinstance 用于数值联合类型时不再扼杀 else 分支:

$ python
def foo(y: int | float) -> None:

    if isinstance(y, float):

        pass

    else:

        print(y)  # was flagged unreachable, y inferred as Never

收窄也能在 while 循环中存活,因此循环体内重新收窄可选属性不再报告虚假的 没有该属性 错误。

(PY-83206PY-83354PY-88265)

类型注解中的字符串

用作 Annotated[...] 内元数据的字符串——例如 Pydantic 判别器字段名——不再被解析为前向引用并标记为未解析。

(PY-48749PY-82245)

可迭代解包与星号表达式

PyCharm 对元组和星号解包的分析可能会丢失类型信息并回退到 Any。将星号值解包到元组中会丢失其元素类型,* 展开会坍缩为 Any,而且几个真正的错误未被报告。星号表达式现在会保留其元素类型:

$ python
def a() -> tuple[int, int]:

    return 2, 3

def b() -> tuple[int, int, int]:

    return (1, *a())  # no more bogus "Expected tuple[int, int, int]"

(PY-12592PY-27205PY-43585PY-90219)

增强赋值

一批误报源于对增强赋值的错误分析。简单地对 int 使用 /= 会产生错误的类型:

$ python
foo = 5

foo /= 2

reveal_type(foo)  # was: int   now: float | int

(PY-80622)

Self 与构造函数返回类型

Self 现在可以通过类型为 type[Self]classmethod 参数正确绑定:

$ python
class A:

    @classmethod

    def bar(cls, y: type[Self]) -> Self: ...

x = A.bar(A)      # was a spurious "Expected type[A], got type[A]"

reveal_type(x)    # was: Any   now: A

构造过程也会尊重 __new____init__ 和元类 __call__。当 __new__ 返回的不是实例时,该返回值就是构造出的类型——即使存在 __init__。同样的修复也适用于显式参数化的调用(如 MyClass[int]())以及作为类属性赋值的 __new__

(PY-89296PY-77611PY-88644PY-89571)

枚举成员:.value.name 的 Literal 类型

读取枚举成员的 .value.name 会产生精确的 Literal,而不是扩展后的 strint,因此对 Literal[...] 目标的赋值可以通过类型检查。这与 mypy 的推断一致:

$ python
from enum import Enum

from typing import Literal

class E(Enum):

    a = "a"

b: Literal["a"] = E.a.value   # was: Expected 'Literal["a"]', got 'str'

n: Literal["a"] = E.a.name    # .name is a Literal too

(PY-61028PY-79198)

从装饰器推断参数类型

当装饰器约束了其接受的 callable 时,被装饰函数的参数现在会根据该约束推断,而不是回退到 Any

$ python
from typing import Callable

def d(fn: Callable[[int], str]): ...

@d

def f(a):

    reveal_type(a)   # was: Any   now: int

(PY-79204)

其他修复

  • 类头中的关键字参数会根据基类的 __init_subclass__ 签名进行验证,并在补全中提供 (PY-79173)。
  • 用作 PEP 695 类型参数边界的 Callable 中的省略号不再报告虚假的 Invalid type expression (PY-83570)。
  • 类型检查器的结果被拆分为细粒度的抑制代码,而不是单一的 PyTypeChecker id,# noinspection 指令接受简化的名称形式。PyTypeChecker 仍然可以作为全部忽略使用 (PY-90265)。

补全与自动导入

更智能的自动导入

自动导入现在明显不那么嘈杂了。以前,如果一个模块已经被导入,PyCharm 会建议添加第二个冗余导入,而不是通过你已有的导入进行限定。快速修复——以及补全弹窗——现在更倾向于复用现有导入。

给定包含 MyClasspkg/src.py,以及一个已经导入该模块的文件,Alt + Enter 会产生:

$ python
from pkg import src  # no longer flagged as unused

src.MyClass

而不是添加 from pkg.src import MyClass。同样的复用逻辑也适用于普通的 import pkg.src,以及第二次 Ctrl + Space 时的自动导入补全。

嵌套类也可以被自动导入了,这是 PyCharm 之前不支持的:

$ python
# mod.py

class Outer:

    class Inner:

        pass

# main.py – Alt+Enter on Inner now offers "Import Outer from mod"

from mod import Outer

value = Outer.Inner()

(PY-87970PY-87971PY-87972PY-88009PY-88016)

unittest.mock.patch() 目标的补全

按字符串目标进行 patch 以前不提供任何代码辅助,因此点分路径必须手动输入。mock.patch(...) 的字符串参数现在可以对模块、类及其属性进行代码补全,并且不再在路径中间建议无效的 as 关键字:

$ python
from unittest import mock

# sample.py defines: class Foo: my_attr = 42

with mock.patch("sample.Foo.my_attr", 14):

    ...

# completion now offers `sample`, `Foo`, and `my_attr`

(PY-89189PY-89191PY-89192)

重写内置方法时的类型化签名

补全重写的 dunder 或内置方法时,会填入完整的注解签名——并自动导入所需的类型——而不是只有裸参数:

$ python
from types import TracebackType

class A:

    def __exit__(self, exc_type: type[BaseException] | None,
                 exc_val: BaseException | None,
                 exc_tb: TracebackType | None): ...

# was: def __exit__(self, exc_type, exc_val, exc_tb):

(PY-79218)


编辑器与检查

类型内联提示

推断出的类型参数现在会在调用点内联显示,因此无需悬停即可看到泛型解析成了什么类型:

$ python
class A[T]:

    def __init__(self, t: T): ...

A[int](1)     # [int] shown as an inlay hint

内联提示中渲染的类型名称(包括返回类型和已解析参数)也是可点击的,因此你可以从提示直接跳转到类型的定义。

(PY-90411PY-90293)

f-string 格式规范验证

PyCharm 已经会验证 str.format() 迷你语言。这些检查同样适用于 f-string,并且 PyCharm 会标记格式化未实现 __format__ 的类型:

$ python
data = 1

f"{data:.2f}"   # ok

f"{data:.2q}"   # now flagged: unsupported format spec

class A: ...

f"{A():d}"      # now flagged: A doesn't support the 'd' format

(PY-51322PY-89760)


重构

Rename 重构在重命名模块本身时,也会更新对模块的引用。以前,重命名会让导入位置指向旧名称:

$ python
# rename provider/provider_module.py → some_module.py

from ..provider import provider_module  # this reference is updated too

(PY-53274)

Refactor | Field 操作现在称为 Attribute,文档中也使用“实例属性”以匹配 Python 术语 (PY-85828)。


结论

总的来说,这些改动让 PyCharm 对 Python 的理解更加精确和可预测:更少的误报、更好的类型推断、更智能的补全,以及更少花费在处理 IDE 误判有效代码的时间上。

这些改进中有许多都始于用户报告的真实示例。如果 PyCharm 仍然误解了你项目中的某种类型模式、框架 API 或其他有效的 Python 代码,请通过 YouTrack 告诉我们——一个小的复现示例可以帮助我们把这些摩擦转化为下一个修复。

试用 PyCharm 2026.2,并告诉我们哪些改进对你的工作流程影响最大。

感谢你使用 PyCharm!