Latest in branch 3.5
3.5.10
Released 05 Sep 2020
(5 years ago)
SoftwarePython
Version3.5
Status
End of life
Initial release3.5.0
12 Sep 2015
(10 years ago)
Latest release3.5.10
05 Sep 2020
(5 years ago)
End of life30 Sep 2020
(Ended 5 years, 8 months ago)
Source codehttps://github.com/python/cpython/tree/v3.5.10
Documentationhttps://docs.python.org/release/3.5.10/
Downloadhttps://www.python.org/downloads/release/python-3510/
Python 3.5 ReleasesView full list

What Is New in Python 3.5

Python 3.5 was released on September 12, 2015. The defining change is the introduction of native async/await syntax, which made asynchronous programming a first-class language feature rather than a generator-based workaround. Additional highlights include the matrix multiplication operator @, extended unpacking generalizations, and the typing module for optional type hints.

Category Change PEP / Reference
New Syntax Native coroutines with async def and await PEP 492
New Syntax Matrix multiplication operator @ and @= PEP 465
New Syntax Unpacking generalizations -- *iterable in more contexts PEP 448
New Modules typing -- optional type hints and generic types PEP 484
New Modules zipapp -- create self-contained Python application archives PEP 441
Standard Library os.scandir() -- faster directory traversal replacing os.listdir() PEP 471
Standard Library math.isclose() for float proximity comparison PEP 485
Standard Library subprocess.run() -- unified subprocess execution API --
Performance memoryview improvements; faster io.BytesIO --
asyncio New transport/protocol APIs; coroutine-based SSL; async with, async for PEP 492

What Changed About Async Programming in Python 3.5?

Native Coroutines with async def / await (PEP 492)

Before 3.5, asyncio coroutines were written using @asyncio.coroutine with yield from -- a generator-based approach that was functional but visually ambiguous. Python 3.5 introduced dedicated async def and await keywords that cannot be used outside async contexts, making coroutine intent explicit.

# Python 3.4 style (generator-based)
@asyncio.coroutine
def fetch(url):
    response = yield from aiohttp.get(url)
    return response

# Python 3.5+ style
async def fetch(url):
    async with aiohttp.ClientSession() as session:
        async with session.get(url) as response:
            return await response.text()

PEP 492 also introduced async with (for async context managers) and async for (for async iterators), rounding out the async syntax.

Matrix Multiplication Operator @ (PEP 465)

The @ operator is reserved for matrix multiplication. NumPy and similar libraries implement __matmul__ to support it. This brings mathematical notation much closer to Python code for linear algebra work.

import numpy as np

A = np.array([[1, 2], [3, 4]])
B = np.array([[5, 6], [7, 8]])

C = A @ B      # Matrix multiplication
# [[19, 22], [43, 50]]

# Previously required:
C = np.dot(A, B)

Extended Unpacking Generalizations (PEP 448)

The * and ** unpacking operators can now appear in more contexts -- multiple times in a single expression, inside lists, dicts, tuples, and function calls.

# Multiple * in one expression
merged = [*list1, *list2, *list3]

# Multiple ** in dict literals
config = {**defaults, **user_config, "timestamp": now}

# Function calls
print(*[1, 2], *[3, 4])  # 1 2 3 4

The typing Module and Optional Type Hints (PEP 484)

Python 3.5 introduced the typing module as a standard home for type hint constructs. Annotations existed before, but there was no standard way to express generic types like "a list of strings." The typing module provides: List, Dict, Optional, Union, Callable, Tuple, Any, and more.

from typing import List, Optional, Dict

def process(items: List[str], limit: Optional[int] = None) -> Dict[str, int]:
    result: Dict[str, int] = {}
    for i, item in enumerate(items[:limit]):
        result[item] = i
    return result

Type hints are still optional and not enforced at runtime -- they exist for static analysis tools like mypy. The typing module in 3.5 was the beginning of Python's gradual typing story.

Standard Library Additions in Python 3.5

os.scandir() -- Faster Directory Listing (PEP 471)

os.scandir() returns an iterator of DirEntry objects that include file attributes alongside names. This avoids a second os.stat() call per file, making it 2-20x faster than os.listdir() followed by os.stat() -- especially on Windows where stat data is embedded in the directory listing.

subprocess.run() -- Unified API

The subprocess.run() function consolidates the functionality of subprocess.call(), subprocess.check_call(), and subprocess.check_output() into a single call with a CompletedProcess result object.

import subprocess

result = subprocess.run(
    ["git", "status"],
    capture_output=True, text=True, check=True
)
print(result.stdout)

math.isclose() (PEP 485)

Comparing floats with == is unreliable due to floating-point representation. math.isclose(a, b) checks that abs(a-b) <= max(rel_tol * max(abs(a), abs(b)), abs_tol), covering both relative and absolute tolerance in one call.

FAQ

Can I use await outside of async def in Python 3.5?
No. await is a syntax error outside of a coroutine function defined with async def. This is a hard constraint -- it prevents accidental use in regular functions where the value would not be awaited.

Does the @ matrix operator work with plain Python lists?
Not out of the box. Lists do not implement __matmul__. The @ operator calls __matmul__ on the left operand (or __rmatmul__ on the right). NumPy arrays support it; standard Python lists do not.

Is the typing module in 3.5 the same as in 3.11+?
No. The module has grown substantially. 3.5 shipped a fairly bare set: Optional, Union, List, Dict, Tuple, Callable, Any, TypeVar, Generic. Many features like Literal, Final, TypedDict, Protocol, ParamSpec, and TypeAlias came in later minor versions. Always check the version-added notes in the docs.

Is os.scandir() safe to use in the same code as os.listdir()?
Yes. They are independent functions. os.scandir() is a drop-in improvement for directory traversal -- prefer it whenever you need type or size information alongside filenames. If you only need names, os.listdir() is fine and slightly simpler.

What is the practical difference between subprocess.run() and subprocess.Popen()?
subprocess.run() blocks until the process completes and returns a CompletedProcess. subprocess.Popen() is lower-level, gives you a handle to the running process, and lets you communicate with it while it runs. Use run() for fire-and-forget commands; use Popen() when you need streaming output, parallel execution, or fine-grained process control.

Releases In Branch 3.5

VersionRelease date
3.5.1005 Sep 2020
(5 years ago)
3.5.10rc119 Aug 2020
(5 years ago)
3.5.901 Nov 2019
(6 years ago)
3.5.829 Oct 2019
(6 years ago)
3.5.8rc212 Oct 2019
(6 years ago)
3.5.8rc109 Sep 2019
(6 years ago)
3.5.717 Mar 2019
(7 years ago)
3.5.7rc104 Mar 2019
(7 years ago)
3.5.602 Aug 2018
(7 years ago)
3.5.6rc120 Jul 2018
(7 years ago)
3.5.504 Feb 2018
(8 years ago)
3.5.5rc123 Jan 2018
(8 years ago)
3.5.407 Aug 2017
(8 years ago)
3.5.4rc124 Jul 2017
(8 years ago)
3.5.316 Jan 2017
(9 years ago)
3.5.3rc102 Jan 2017
(9 years ago)
3.5.225 Jun 2016
(9 years ago)
3.5.2rc112 Jun 2016
(9 years ago)
3.5.106 Dec 2015
(10 years ago)
3.5.1rc122 Nov 2015
(10 years ago)
3.5.012 Sep 2015
(10 years ago)
3.5.0rc409 Sep 2015
(10 years ago)
3.5.0rc307 Sep 2015
(10 years ago)
3.5.0rc225 Aug 2015
(10 years ago)
3.5.0rc110 Aug 2015
(10 years ago)
3.5.0b425 Jul 2015
(10 years ago)
3.5.0b305 Jul 2015
(10 years ago)
3.5.0b231 May 2015
(11 years ago)
3.5.0b124 May 2015
(11 years ago)
3.5.0a419 Apr 2015
(11 years ago)
3.5.0a329 Mar 2015
(11 years ago)
3.5.0a208 Mar 2015
(11 years ago)
3.5.0a108 Feb 2015
(11 years ago)