Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 1d857da

Browse filesBrowse files
authored
GH-77273: Better bytecodes for f-strings (GH-6132)
1 parent 307bcea commit 1d857da
Copy full SHA for 1d857da

File tree

15 files changed

+519
-479
lines changed
Filter options

15 files changed

+519
-479
lines changed

‎Doc/library/dis.rst

Copy file name to clipboardExpand all lines: Doc/library/dis.rst
+37-16Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,26 +1465,47 @@ iterations of the loop.
14651465
an argument from two-byte to four-byte.
14661466

14671467

1468-
.. opcode:: FORMAT_VALUE (flags)
1468+
.. opcode:: CONVERT_VALUE (oparg)
14691469

1470-
Used for implementing formatted literal strings (f-strings). Pops
1471-
an optional *fmt_spec* from the stack, then a required *value*.
1472-
*flags* is interpreted as follows:
1470+
Convert value to a string, depending on ``oparg``::
14731471

1474-
* ``(flags & 0x03) == 0x00``: *value* is formatted as-is.
1475-
* ``(flags & 0x03) == 0x01``: call :func:`str` on *value* before
1476-
formatting it.
1477-
* ``(flags & 0x03) == 0x02``: call :func:`repr` on *value* before
1478-
formatting it.
1479-
* ``(flags & 0x03) == 0x03``: call :func:`ascii` on *value* before
1480-
formatting it.
1481-
* ``(flags & 0x04) == 0x04``: pop *fmt_spec* from the stack and use
1482-
it, else use an empty *fmt_spec*.
1472+
value = STACK.pop()
1473+
result = func(value)
1474+
STACK.push(result)
14831475

1484-
Formatting is performed using :c:func:`PyObject_Format`. The
1485-
result is pushed on the stack.
1476+
* ``oparg == 1``: call :func:`str` on *value*
1477+
* ``oparg == 2``: call :func:`repr` on *value*
1478+
* ``oparg == 3``: call :func:`ascii` on *value*
14861479

1487-
.. versionadded:: 3.6
1480+
Used for implementing formatted literal strings (f-strings).
1481+
1482+
.. versionadded:: 3.13
1483+
1484+
1485+
.. opcode:: FORMAT_SIMPLE
1486+
1487+
Formats the value on top of stack::
1488+
1489+
value = STACK.pop()
1490+
result = value.__format__("")
1491+
STACK.push(result)
1492+
1493+
Used for implementing formatted literal strings (f-strings).
1494+
1495+
.. versionadded:: 3.13
1496+
1497+
.. opcode:: FORMAT_SPEC
1498+
1499+
Formats the given value with the given format spec::
1500+
1501+
spec = STACK.pop()
1502+
value = STACK.pop()
1503+
result = value.__format__(spec)
1504+
STACK.push(result)
1505+
1506+
Used for implementing formatted literal strings (f-strings).
1507+
1508+
.. versionadded:: 3.13
14881509

14891510

14901511
.. opcode:: MATCH_CLASS (count)

‎Include/internal/pycore_opcode.h

Copy file name to clipboardExpand all lines: Include/internal/pycore_opcode.h
+25-25Lines changed: 25 additions & 25 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Include/opcode.h

Copy file name to clipboardExpand all lines: Include/opcode.h
+44-42Lines changed: 44 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Lib/dis.py

Copy file name to clipboardExpand all lines: Lib/dis.py
+5-14Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,8 @@
2525
_have_code = (types.MethodType, types.FunctionType, types.CodeType,
2626
classmethod, staticmethod, type)
2727

28-
FORMAT_VALUE = opmap['FORMAT_VALUE']
29-
FORMAT_VALUE_CONVERTERS = (
30-
(None, ''),
31-
(str, 'str'),
32-
(repr, 'repr'),
33-
(ascii, 'ascii'),
34-
)
28+
CONVERT_VALUE = opmap['CONVERT_VALUE']
29+
3530
SET_FUNCTION_ATTRIBUTE = opmap['SET_FUNCTION_ATTRIBUTE']
3631
FUNCTION_ATTR_FLAGS = ('defaults', 'kwdefaults', 'annotations', 'closure')
3732

@@ -579,13 +574,9 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
579574
elif deop in hascompare:
580575
argval = cmp_op[arg>>4]
581576
argrepr = argval
582-
elif deop == FORMAT_VALUE:
583-
argval, argrepr = FORMAT_VALUE_CONVERTERS[arg & 0x3]
584-
argval = (argval, bool(arg & 0x4))
585-
if argval[1]:
586-
if argrepr:
587-
argrepr += ', '
588-
argrepr += 'with format'
577+
elif deop == CONVERT_VALUE:
578+
argval = (None, str, repr, ascii)[arg]
579+
argrepr = ('', 'str', 'repr', 'ascii')[arg]
589580
elif deop == SET_FUNCTION_ATTRIBUTE:
590581
argrepr = ', '.join(s for i, s in enumerate(FUNCTION_ATTR_FLAGS)
591582
if arg & (1<<i))

‎Lib/importlib/_bootstrap_external.py

Copy file name to clipboardExpand all lines: Lib/importlib/_bootstrap_external.py
+4-2Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,9 @@ def _write_atomic(path, data, mode=0o666):
447447
# Python 3.12b1 3531 (Add PEP 695 changes)
448448
# Python 3.13a1 3550 (Plugin optimizer support)
449449
# Python 3.13a1 3551 (Compact superinstructions)
450-
# Python 3.13a1 3552 (Add SET_FUNCTION_ATTRIBUTE)
450+
# Python 3.13a1 3552 (Remove LOAD_FAST__LOAD_CONST and LOAD_CONST__LOAD_FAST)
451+
# Python 3.13a1 3553 (Add SET_FUNCTION_ATTRIBUTE)
452+
# Python 3.13a1 3554 (more efficient bytecodes for f-strings)
451453

452454
# Python 3.14 will start with 3600
453455

@@ -464,7 +466,7 @@ def _write_atomic(path, data, mode=0o666):
464466
# Whenever MAGIC_NUMBER is changed, the ranges in the magic_values array
465467
# in PC/launcher.c must also be updated.
466468

467-
MAGIC_NUMBER = (3552).to_bytes(2, 'little') + b'\r\n'
469+
MAGIC_NUMBER = (3554).to_bytes(2, 'little') + b'\r\n'
468470

469471
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
470472

‎Lib/opcode.py

Copy file name to clipboardExpand all lines: Lib/opcode.py
+4-1Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,9 @@ def pseudo_op(name, op, real_ops):
110110
def_op('CHECK_EXC_MATCH', 36)
111111
def_op('CHECK_EG_MATCH', 37)
112112

113+
def_op('FORMAT_SIMPLE', 40)
114+
def_op('FORMAT_WITH_SPEC', 41)
115+
113116
def_op('WITH_EXCEPT_START', 49)
114117
def_op('GET_AITER', 50)
115118
def_op('GET_ANEXT', 51)
@@ -213,9 +216,9 @@ def pseudo_op(name, op, real_ops):
213216
def_op('RESUME', 151) # This must be kept in sync with deepfreeze.py
214217
def_op('MATCH_CLASS', 152)
215218

216-
def_op('FORMAT_VALUE', 155)
217219
def_op('BUILD_CONST_KEY_MAP', 156)
218220
def_op('BUILD_STRING', 157)
221+
def_op('CONVERT_VALUE', 158)
219222

220223
def_op('LIST_EXTEND', 162)
221224
def_op('SET_UPDATE', 163)

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.