pyupgrade

pyupgrade

智能更新Python代码语法的开源工具

pyupgrade是一个开源的Python代码语法升级工具,可作为独立程序或pre-commit钩子使用。它能自动将旧版Python语法转换为新版特性,支持集合字面量、字典推导式、f-strings等多种语法优化。该工具有助于开发者保持代码的现代化和一致性,提高Python项目的质量。

pyupgradePython语法升级代码重构pre-commit静态代码分析Github开源项目

构建状态 pre-commit.ci 状态

pyupgrade

一个用于自动升级较新版本语言语法的工具(和 pre-commit 钩子)。

安装

pip install pyupgrade

作为 pre-commit 钩子使用

使用说明请参见 pre-commit

示例 .pre-commit-config.yaml

- repo: https://github.com/asottile/pyupgrade rev: v3.17.0 hooks: - id: pyupgrade

已实现的功能

集合字面量

-set(()) +set() -set([]) +set() -set((1,)) +{1} -set((1, 2)) +{1, 2} -set([1, 2]) +{1, 2} -set(x for x in y) +{x for x in y} -set([x for x in y]) +{x for x in y}

字典推导式

-dict((a, b) for a, b in y) +{a: b for a, b in y} -dict([(a, b) for a, b in y]) +{a: b for a, b in y}

替换 collections.defaultdict 调用中不必要的 lambda 函数

-defaultdict(lambda: []) +defaultdict(list) -defaultdict(lambda: list()) +defaultdict(list) -defaultdict(lambda: {}) +defaultdict(dict) -defaultdict(lambda: dict()) +defaultdict(dict) -defaultdict(lambda: ()) +defaultdict(tuple) -defaultdict(lambda: tuple()) +defaultdict(tuple) -defaultdict(lambda: set()) +defaultdict(set) -defaultdict(lambda: 0) +defaultdict(int) -defaultdict(lambda: 0.0) +defaultdict(float) -defaultdict(lambda: 0j) +defaultdict(complex) -defaultdict(lambda: '') +defaultdict(str)

格式说明符

-'{0} {1}'.format(1, 2) +'{} {}'.format(1, 2) -'{0}' '{1}'.format(1, 2) +'{}' '{}'.format(1, 2)

printf 风格的字符串格式化

适用性:

  • 除非传递了 --keep-percent-format 参数。
-'%s %s' % (a, b) +'{} {}'.format(a, b) -'%r %2f' % (a, b) +'{!r} {:2f}'.format(a, b) -'%(a)s %(b)s' % {'a': 1, 'b': 2} +'{a} {b}'.format(a=1, b=2)

Unicode 字面量

-u'foo' +'foo' -u"foo" +'foo' -u'''foo''' +'''foo'''

无效的转义序列

# 只包含无效序列的字符串变为原始字符串 -'\d' +r'\d' # 混合有效和无效序列的字符串会被转义 -'\n\d' +'\n\\d' -u'\d' +r'\d' # 这修复了 python3.3+ 中的语法错误 -'\N' +r'\N'

与常量字面量进行 is / is not 比较

在 python3.8+ 中,与字面量的比较会产生 SyntaxWarning,因为这些比较的成功与否取决于具体实现(由于常见对象缓存)。

-x is 5 +x == 5 -x is not 5 +x != 5 -x is 'foo' +x == 'foo'

.encode() 到字节字面量

-'foo'.encode() +b'foo' -'foo'.encode('ascii') +b'foo' -'foo'.encode('utf-8') +b'foo' -u'foo'.encode() +b'foo' -'\xa0'.encode('latin1') +b'\xa0'

print(...) 中多余的括号

修复 python-modernize/python-modernize#178 问题

# 正确:打印空元组 print(()) # 正确:打印元组 print((1,)) # 正确:括号内的生成器参数 sum((i for i in range(3)), []) # 修复后: -print(("foo")) +print("foo")

常量折叠 isinstance / issubclass / except

-isinstance(x, (int, int)) +isinstance(x, int) -issubclass(y, (str, str)) +issubclass(y, str) try: raises() -except (Error1, Error1, Error2): +except (Error1, Error2): pass

unittest 已弃用的别名

已弃用的 unittest 方法别名 重写为非弃用形式。

from unittest import TestCase class MyTests(TestCase): def test_something(self): - self.failUnlessEqual(1, 1) + self.assertEqual(1, 1) - self.assertEquals(1, 1) + self.assertEqual(1, 1)

super() 调用

class C(Base): def f(self): - super(C, self).f() + super().f()

"新式"类

重写类声明

-class C(object): pass +class C: pass -class C(B, object): pass +class C(B): pass

移除 __metaclass__ = type 声明

class C: - __metaclass__ = type

强制 str("native") 字面量

-str() +'' -str("foo") +"foo"

.encode("utf-8")

-"foo".encode("utf-8") +"foo".encode()

# coding: ... 注释

根据 PEP 3120,Python 源代码的默认编码为 UTF-8

-# coding: utf-8 x = 1

移除 __future__ 导入

可用性:

  • 默认移除 nested_scopesgeneratorswith_statementabsolute_importdivisionprint_functionunicode_literals
  • --py37-plus 还会移除 generator_stop
-from __future__ import with_statement

移除不必要的 py3 兼容性导入

-from io import open -from six.moves import map -from builtins import object # python-future

导入替换

可用性:

  • --py36-plus(及其他)将替换导入

另见 reorder-python-imports

一些例子:

-from collections import deque, Mapping +from collections import deque +from collections.abc import Mapping
-from typing import Sequence +from collections.abc import Sequence
-from typing_extensions import Concatenate +from typing import Concatenate

重写 mock 导入

可用性:

-from mock import patch +from unittest.mock import patch

yield => yield from

def f(): - for x in y: - yield x + yield from y - for a, b in c: - yield (a, b) + yield from c

Python2 和旧 Python3.x 代码块

import sys -if sys.version_info < (3,): # 也理解 `six.PY2`(及其否定)、`six.PY3`(及其否定) - print('py2') -else: - print('py3') +print('py3')

可用性:

  • --py36-plus 将移除 Python <= 3.5 的代码块
  • --py37-plus 将移除 Python <= 3.6 的代码块
  • 以此类推
# 此示例使用 --py36-plus import sys -if sys.version_info < (3, 6): - print('py3.5') -else: - print('py3.6+') +print('py3.6+') -if sys.version_info <= (3, 5): - print('py3.5') -else: - print('py3.6+') +print('py3.6+') -if sys.version_info >= (3, 6): - print('py3.6+') -else: - print('py3.5') +print('py3.6+')

注意,没有 elseif 块不会被重写,因为这可能会引入语法错误。

移除 six 兼容性代码

-six.text_type +str -six.binary_type +bytes -six.class_types +(type,) -six.string_types +(str,) -six.integer_types +(int,) -six.unichr +chr -six.iterbytes +iter -six.print_(...) +print(...) -six.exec_(c, g, l) +exec(c, g, l) -six.advance_iterator(it) +next(it) -six.next(it) +next(it) -six.callable(x) +callable(x) -six.moves.range(x) +range(x) -six.moves.xrange(x) +range(x) -from six import text_type -text_type +str -@six.python_2_unicode_compatible class C: def __str__(self): return u'C()' -class C(six.Iterator): pass +class C: pass -class C(six.with_metaclass(M, B)): pass +class C(B, metaclass=M): pass -@six.add_metaclass(M) -class C(B): pass +class C(B, metaclass=M): pass -isinstance(..., six.class_types) +isinstance(..., type) -issubclass(..., six.integer_types) +issubclass(..., int) -isinstance(..., six.string_types) +isinstance(..., str) -six.b('...') +b'...' -six.u('...') +'...' -six.byte2int(bs) +bs[0] -six.indexbytes(bs, i) +bs[i] -six.int2byte(i) +bytes((i,)) -six.iteritems(dct) +dct.items() -six.iterkeys(dct) +dct.keys() -six.itervalues(dct) +dct.values() -next(six.iteritems(dct)) +next(iter(dct.items())) -next(six.iterkeys(dct)) +next(iter(dct.keys())) -next(six.itervalues(dct)) +next(iter(dct.values())) -six.viewitems(dct) +dct.items() -six.viewkeys(dct) +dct.keys() -six.viewvalues(dct) +dct.values() -six.create_unbound_method(fn, cls) +fn -six.get_unbound_function(meth) +meth -six.get_method_function(meth) +meth.__func__ -six.get_method_self(meth) +meth.__self__ -six.get_function_closure(fn) +fn.__closure__ -six.get_function_code(fn) +fn.__code__ -six.get_function_defaults(fn) +fn.__defaults__ -six.get_function_globals(fn) +fn.__globals__ -six.raise_from(exc, exc_from) +raise exc from exc_from -six.reraise(tp, exc, tb) +raise exc.with_traceback(tb) -six.reraise(*sys.exc_info()) +raise -six.assertCountEqual(self, a1, a2) +self.assertCountEqual(a1, a2) -six.assertRaisesRegex(self, e, r, fn) +self.assertRaisesRegex(e, r, fn) -six.assertRegex(self, s, r) +self.assertRegex(s, r) # 注意:仅适用于*字面值* -six.ensure_binary('...') +b'...' -six.ensure_str('...') +'...' -six.ensure_text('...') +'...'

open 别名

-with io.open('f.txt') as f: +with open('f.txt') as f: ...

冗余的 open 模式

-open("foo", "U") +open("foo") -open("foo", "Ur") +open("foo") -open("foo", "Ub") +open("foo", "rb") -open("foo", "rUb") +open("foo", "rb") -open("foo", "r") +open("foo") -open("foo", "rt") +open("foo") -open("f", "r", encoding="UTF-8") +open("f", encoding="UTF-8") -open("f", "wt") +open("f", "w")

OSError 别名

# 也理解: # - IOError # - WindowsError # - mmap.error 和使用 `from mmap import error` # - select.error 和使用 `from select import error` # - socket.error 和使用 `from socket import error`

def throw():

  • raise EnvironmentError('boom')
  • raise OSError('boom')

def catch(): try: throw()

  • except EnvironmentError:
  • except OSError: handle_error()

### `TimeoutError` 别名

可用性:
- `--py310-plus` 用于 `socket.timeout`
- `--py311-plus` 用于 `asyncio.TimeoutError`

```diff

def throw(a):
    if a:
-        raise asyncio.TimeoutError('boom')
+        raise TimeoutError('boom')
    else:
-        raise socket.timeout('boom')
+        raise TimeoutError('boom')

def catch(a):
    try:
        throw(a)
-    except (asyncio.TimeoutError, socket.timeout):
+    except TimeoutError:
        handle_error()

typing.Text str 别名

-def f(x: Text) -> None: +def f(x: str) -> None: ...

解包列表推导式

-foo, bar, baz = [fn(x) for x in items] +foo, bar, baz = (fn(x) for x in items)

xml.etree.cElementTree 重写为 xml.etree.ElementTree

-import xml.etree.cElementTree as ET +import xml.etree.ElementTree as ET -from xml.etree.cElementTree import XML +from xml.etree.ElementTree import XML

重写原始类型的 type

-type('') +str -type(b'') +bytes -type(0) +int -type(0.) +float

typing.NamedTuple / typing.TypedDict py36+ 语法

可用性:

  • 命令行传入 --py36-plus
-NT = typing.NamedTuple('NT', [('a', int), ('b', Tuple[str, ...])]) +class NT(typing.NamedTuple): + a: int + b: Tuple[str, ...] -D1 = typing.TypedDict('D1', a=int, b=str) +class D1(typing.TypedDict): + a: int + b: str -D2 = typing.TypedDict('D2', {'a': int, 'b': str}) +class D2(typing.TypedDict): + a: int + b: str

f-字符串

可用性:

  • 命令行传入 --py36-plus
-'{foo} {bar}'.format(foo=foo, bar=bar) +f'{foo} {bar}' -'{} {}'.format(foo, bar) +f'{foo} {bar}' -'{} {}'.format(foo.bar, baz.womp) +f'{foo.bar} {baz.womp}' -'{} {}'.format(f(), g()) +f'{f()} {g()}' -'{x}'.format(**locals()) +f'{x}'

注意: pyupgrade 有意保守,如果它会使表达式变长或者替换参数过于复杂(因为这可能降低可读性),它就不会创建 f-字符串。

subprocess.run: 用 text 替换 universal_newlines

可用性:

  • 命令行传入 --py37-plus
-output = subprocess.run(['foo'], universal_newlines=True) +output = subprocess.run(['foo'], text=True)

subprocess.run: 用 capture_output=True 替换 stdout=subprocess.PIPE, stderr=subprocess.PIPE

可用性:

  • 命令行传入 --py37-plus
-output = subprocess.run(['foo'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) +output = subprocess.run(['foo'], capture_output=True)

移除 @functools.lru_cache() 中的括号

可用性:

  • 命令行传入 --py38-plus
import functools -@functools.lru_cache() +@functools.lru_cache def expensive(): ...

shlex.join

可用性:

  • 命令行传入 --py38-plus
-' '.join(shlex.quote(arg) for arg in cmd) +shlex.join(cmd)

用简写替换 @functools.lru_cache(maxsize=None)

可用性:

  • 命令行传入 --py39-plus
import functools -@functools.lru_cache(maxsize=None) +@functools.cache def expensive(): ...

pep 585 类型注解重写

可用性:

  • 文件导入 from __future__ import annotations
    • 除非命令行传入 --keep-runtime-typing
  • 命令行传入 --py39-plus
-def f(x: List[str]) -> None: +def f(x: list[str]) -> None: ...

pep 604 类型注解重写

可用性:

  • 文件导入 from __future__ import annotations
    • 除非命令行传入 --keep-runtime-typing
  • 命令行传入 --py310-plus
-def f() -> Optional[str]: +def f() -> str | None: ...
-def f() -> Union[int, str]: +def f() -> int | str: ...

pep 696 TypeVar 默认值

可用性:

  • 文件导入 from __future__ import annotations
    • 除非命令行传入 --keep-runtime-typing
  • 命令行传入 --py313-plus
-def f() -> Generator[int, None, None]: +def f() -> Generator[int]: yield 1
-async def f() -> AsyncGenerator[int, None]: +async def f() -> AsyncGenerator[int]: yield 1

移除带引号的注解

可用性:

  • 文件导入 from __future__ import annotations
-def f(x: 'queue.Queue[int]') -> C: +def f(x: queue.Queue[int]) -> C:

使用 datetime.UTC 别名

可用性:

  • 命令行传入 --py311-plus
import datetime -datetime.timezone.utc +datetime.UTC

编辑推荐精选

TRAE编程

TRAE编程

AI辅助编程,代码自动修复

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
蛙蛙写作

蛙蛙写作

AI小说写作助手,一站式润色、改写、扩写

蛙蛙写作—国内先进的AI写作平台,涵盖小说、学术、社交媒体等多场景。提供续写、改写、润色等功能,助力创作者高效优化写作流程。界面简洁,功能全面,适合各类写作者提升内容品质和工作效率。

AI辅助写作AI工具蛙蛙写作AI写作工具学术助手办公助手营销助手AI助手
问小白

问小白

全能AI智能助手,随时解答生活与工作的多样问题

问小白,由元石科技研发的AI智能助手,快速准确地解答各种生活和工作问题,包括但不限于搜索、规划和社交互动,帮助用户在日常生活中提高效率,轻松管理个人事务。

热门AI助手AI对话AI工具聊天机器人
Transly

Transly

实时语音翻译/同声传译工具

Transly是一个多场景的AI大语言模型驱动的同声传译、专业翻译助手,它拥有超精准的音频识别翻译能力,几乎零延迟的使用体验和支持多国语言可以让你带它走遍全球,无论你是留学生、商务人士、韩剧美剧爱好者,还是出国游玩、多国会议、跨国追星等等,都可以满足你所有需要同传的场景需求,线上线下通用,扫除语言障碍,让全世界的语言交流不再有国界。

讯飞智文

讯飞智文

一键生成PPT和Word,让学习生活更轻松

讯飞智文是一个利用 AI 技术的项目,能够帮助用户生成 PPT 以及各类文档。无论是商业领域的市场分析报告、年度目标制定,还是学生群体的职业生涯规划、实习避坑指南,亦或是活动策划、旅游攻略等内容,它都能提供支持,帮助用户精准表达,轻松呈现各种信息。

AI办公办公工具AI工具讯飞智文AI在线生成PPTAI撰写助手多语种文档生成AI自动配图热门
讯飞星火

讯飞星火

深度推理能力全新升级,全面对标OpenAI o1

科大讯飞的星火大模型,支持语言理解、知识问答和文本创作等多功能,适用于多种文件和业务场景,提升办公和日常生活的效率。讯飞星火是一个提供丰富智能服务的平台,涵盖科技资讯、图像创作、写作辅助、编程解答、科研文献解读等功能,能为不同需求的用户提供便捷高效的帮助,助力用户轻松获取信息、解决问题,满足多样化使用场景。

热门AI开发模型训练AI工具讯飞星火大模型智能问答内容创作多语种支持智慧生活
Spark-TTS

Spark-TTS

一种基于大语言模型的高效单流解耦语音令牌文本到语音合成模型

Spark-TTS 是一个基于 PyTorch 的开源文本到语音合成项目,由多个知名机构联合参与。该项目提供了高效的 LLM(大语言模型)驱动的语音合成方案,支持语音克隆和语音创建功能,可通过命令行界面(CLI)和 Web UI 两种方式使用。用户可以根据需求调整语音的性别、音高、速度等参数,生成高质量的语音。该项目适用于多种场景,如有声读物制作、智能语音助手开发等。

咔片PPT

咔片PPT

AI助力,做PPT更简单!

咔片是一款轻量化在线演示设计工具,借助 AI 技术,实现从内容生成到智能设计的一站式 PPT 制作服务。支持多种文档格式导入生成 PPT,提供海量模板、智能美化、素材替换等功能,适用于销售、教师、学生等各类人群,能高效制作出高品质 PPT,满足不同场景演示需求。

讯飞绘文

讯飞绘文

选题、配图、成文,一站式创作,让内容运营更高效

讯飞绘文,一个AI集成平台,支持写作、选题、配图、排版和发布。高效生成适用于各类媒体的定制内容,加速品牌传播,提升内容营销效果。

热门AI辅助写作AI工具讯飞绘文内容运营AI创作个性化文章多平台分发AI助手
材料星

材料星

专业的AI公文写作平台,公文写作神器

AI 材料星,专业的 AI 公文写作辅助平台,为体制内工作人员提供高效的公文写作解决方案。拥有海量公文文库、9 大核心 AI 功能,支持 30 + 文稿类型生成,助力快速完成领导讲话、工作总结、述职报告等材料,提升办公效率,是体制打工人的得力写作神器。

下拉加载更多