Free Python reference · JavaScript timeline
Python 3.8: Assign inside expressions when it helps
The walrus operator can reuse a computed value, positional-only parameters clarify APIs, and f-strings can label debugging values.
Released · Editorial review October 25, 2026
Introduced in Python 3.8 · Syntax
The := walrus operator
An assignment expression computes a value, binds it to a name, and makes that value available to the surrounding expression. It is useful when a calculation is needed both to decide what to do and to perform the work. Ordinary = is an assignment statement; == compares values; := binds a name while producing a value.
Parentheses and precedence. In if (size := len(items)) > 2, size receives the length. Writing if size := len(items) > 2 instead assigns the comparison result, a boolean. Parentheses make the intended grouping explicit. A standalone assignment expression also needs parentheses, although ordinary assignment is usually clearer there. The target must be a simple name, not an attribute or subscript.
Truthiness is a separate choice. if (position := text.find("x")): is a bug: index zero is falsey, while the missing marker -1 is truthy. Compare the saved result with the actual success condition. Similarly, the loop below stops on the explicit None sentinel while accepting a numeric zero.
Comprehensions and scope. In the final example, clean is bound in the containing scope rather than being isolated like the comprehension's iteration variable. Do not rely on its last value after an empty comprehension: the assignment might never have happened. Choose an ordinary loop when that scope behavior makes the code harder to follow.
Use := when it removes a repeated operation or a bookkeeping step. If an assignment on its own line tells the story more clearly, keep it. Shorter code is not automatically easier code.
Earlier approach
size = len(items) if size > 2: print(size)
Context fragment; read it with the example below.
Worked example
Minimum Python 3.8
items = ["a", "b", "c"] if (size := len(items)) > 2: print(size) text = "xray" if (position := text.find("x")) != -1: print(position) values = iter([0, 5, None]) while (value := next(values)) is not None: print(value) names = [" Ada ", " ", "Mina"] cleaned = [clean for name in names if (clean := name.strip())] print(cleaned)
Expected output
3
0
0
5
['Ada', 'Mina']
Example checked with CPython 3.14.8, CPython 3.15.0, Pyodide Python 3.13.2.
Common mistake
Do not confuse saving a value with testing its truthiness. In comprehensions, walrus bindings can outlive the comprehension; they cannot rebind its iteration variable.
Try it yourself
Change the comparison to if (size := len(items) > 2): and predict the type and value of size. Then rewrite the name-cleaning comprehension as an ordinary loop.
Read more: Python 3.8 release notes · PEP 572
Introduced in Python 3.8 · Syntax
Positional-only parameters with /
A slash in a function signature marks the preceding parameters as positional-only. Callers must supply those arguments by position. Parameters after / can still accept keywords unless another marker changes their calling convention.
The * marker introduces keyword-only parameters. Combining both markers lets an API distinguish its main input from named options. This can also let a library rename an internal parameter without breaking callers that would otherwise use that name.
The example permits render("status", suffix="!") but deliberately rejects render(text="status"). The exception is caught so you can see the failure without depending on an exact error message.
Worked example
Minimum Python 3.8
def render(text, /, *, suffix="."): return text + suffix print(render("status", suffix="!")) try: render(text="status") except TypeError: print("text must be positional")
Expected output
status!
text must be positional
Example checked with CPython 3.14.8, CPython 3.15.0, Pyodide Python 3.13.2.
Common mistake
The slash is a signature marker, not an argument. Do not require positional-only arguments unless the API benefits from that restriction.
Try it yourself
Add a normal optional parameter between / and *. Which arguments can now be supplied either way?
Read more: Python 3.8 release notes · PEP 570
Introduced in Python 3.8 · Syntax
Self-labeling f-strings with =
Put = after an f-string expression to include its source text and value. This is useful for a quick local diagnostic when several values are printed together.
Without a format specification, the debug form uses a representation suitable for inspecting values, so strings include quotes. You can still add a numeric format such as .1f after the equals sign.
This is a display feature rather than assignment. Spaces in the expression can appear in the label, so keep the source spelling consistent when comparing expected output.
Worked example
Minimum Python 3.8
name = "Ada" ratio = 2 / 3 print(f"{name=}") print(f"{ratio=:.1f}")
Expected output
name='Ada'
ratio=0.7
Example checked with CPython 3.14.8, CPython 3.15.0, Pyodide Python 3.13.2.
Common mistake
Debug output may expose sensitive values. Use deliberate logging in an application and choose which fields to include.
Try it yourself
Print the length of name with the debug form. Predict the entire label as well as the numeric result.
Read more: Python 3.8 release notes
Recap
The walrus operator can reuse a computed value, positional-only parameters clarify APIs, and f-strings can label debugging values. Prefer the clearest form that works on your project's supported Python versions.
Read the full Python 3.8 release notes →