{ "cells": [ { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# What's new in python 3.6 to 3.10" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## What is missing\n", "\n", "* Async things\n", "* customization of class creation\n", "* Windows console encoding\n", "* CPython news\n", "* Timezones\n", "* Decorators grammar relaxed\n", "* Speedup due to vectorcall" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Python 3.6" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Formatted string literals (PEP 498)\n", "\n", "Formatted string literals are prefixed with 'f' and are similar to the format strings accepted by str.format(). They contain replacement fields surrounded by curly braces. The replacement fields are expressions, which are evaluated at run time, and then formatted using the format() protocol:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "File 000031.txt contains the value 12.77\n" ] } ], "source": [ "d = 12.768217131912\n", "i = 31\n", "print(f\"File {i:06}.txt contains the value {d:.2f}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "See https://realpython.com/python-f-strings/ for more details." ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Type Hints and Syntax for variable annotations (PEP 484 and PEP 526)\n", "\n", "Type hinting is a formal solution to statically indicate the type of a value within your Python code. " ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello, Mira'" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# greetings.py\n", "def greet(name: str) -> str:\n", " return(f\"Hello, {name}\")\n", "\n", "greet(\"Mira\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "type hints are not checked during runtime " ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello, 6'" ] }, "execution_count": 30, "metadata": {}, "output_type": "execute_result" } ], "source": [ "greet(6)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Mypy\n", "\n", "Mypy is an optional static type checker for Python that aims to combine the benefits of dynamic (or “duck”) typing and static typing. \n", "\n", "https://realpython.com/lessons/type-checking-mypy/\n", "\n", "\n", "```python\n", "# greetings.py\n", "def greet(name: str) -> str:\n", " return(f\"Hello, {name}\")\n", "\n", "greet(\"Mira\")\n", "greet(6)\n", "```" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "greetings.py:6: error: Argument 1 to \"greet\" has incompatible type \"int\"; expected \"str\"\n", "Found 1 error in 1 file (checked 1 source file)\n" ] } ], "source": [ "!mypy greetings.py" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Union" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "from typing import Union\n", "\n", "def print_key(key: Union[int, str]):\n", " print(f\"key={key}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Optional" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "from typing import Optional\n", "\n", "def foo(arg: Optional[int] = None) -> None:\n", " return None" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "### Iterables" ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "slideshow": { "slide_type": "-" } }, "outputs": [], "source": [ "Vector = list[float]\n", "\n", "def scale(scalar: float, vector: Vector) -> Vector:\n", " return [scalar * num for num in vector]\n", "\n", "# typechecks; a list of floats qualifies as a Vector.\n", "new_vector = scale(2.0, [1.0, -4.2, 5.4])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "https://mypy.readthedocs.io/en/stable/cheat_sheet_py3.html#cheat-sheet-py3" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Underscores in Numeric Literals (PEP 515)\n", "\n", "adds the ability to use underscores in numeric literals for improved readability." ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1000000000000000" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "1_000_000_000_000_000\n" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "4294967295" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "0x_FF_FF_FF_FF" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "subslide" } }, "source": [ "The string formatting language also now has support for the '_' option to signal the use of an underscore for a thousands separator for floating point presentation types and for integer presentation type 'd'. For integer presentation types 'b', 'o', 'x', and 'X', underscores will be inserted every 4 digits:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'1_000_000'" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'{:_}'.format(1000000)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'ffff_ffff'" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'{:_x}'.format(0xFFFFFFFF)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ " ## Adding a file system path protocol (PEP 519) - `pathlib`\n", " \n", " https://realpython.com/python-pathlib/\n", " \n", " http://zetcode.com/python/pathlib/" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "WindowsPath('~/projects/ZDO/python_news')" ] }, "execution_count": 77, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from pathlib import Path\n", "pth = Path(\"~/projects/ZDO/python_news/\")\n", "pth" ] }, { "cell_type": "code", "execution_count": 78, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "WindowsPath('C:/Users/Jirik/projects/ZDO/python_news')" ] }, "execution_count": 78, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pth = pth.expanduser()\n", "pth" ] }, { "cell_type": "code", "execution_count": 79, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 79, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pth.exists()" ] }, { "cell_type": "code", "execution_count": 80, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "WindowsPath('C:/Users/Jirik/projects/ZDO')" ] }, "execution_count": 80, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pth.parent" ] }, { "cell_type": "code", "execution_count": 81, "metadata": { "slideshow": { "slide_type": "subslide" } }, "outputs": [ { "data": { "text/plain": [ "[WindowsPath('C:/Users/Jirik/projects/ZDO/python_news/.ipynb_checkpoints'),\n", " WindowsPath('C:/Users/Jirik/projects/ZDO/python_news/.mypy_cache'),\n", " WindowsPath('C:/Users/Jirik/projects/ZDO/python_news/greetings.py'),\n", " WindowsPath('C:/Users/Jirik/projects/ZDO/python_news/python_36_310.ipynb')]" ] }, "execution_count": 81, "metadata": {}, "output_type": "execute_result" } ], "source": [ "list(pth.glob('*'))" ] }, { "cell_type": "code", "execution_count": 58, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "WindowsPath('C:/Users/Jirik/projects/ZDO/python_news/greetings.py')" ] }, "execution_count": 58, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fn = pth / \"greetings.py\"\n", "fn" ] }, { "cell_type": "code", "execution_count": 59, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'greetings'" ] }, "execution_count": 59, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fn.stem" ] }, { "cell_type": "code", "execution_count": 65, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'.py'" ] }, "execution_count": 65, "metadata": {}, "output_type": "execute_result" } ], "source": [ "fn.suffix" ] }, { "cell_type": "code", "execution_count": 83, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "WindowsPath('projects/ZDO/python_news')" ] }, "execution_count": 83, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pth.relative_to(Path.home())" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Preserving Keyword Argument Order (PEP 468 and pep 528)\n", "\n", "The dict type now uses a “compact” representation based on a proposal by Raymond Hettinger which was first implemented by PyPy. The memory usage of the new dict() is between 20% and 25% smaller compared to Python 3.5." ] }, { "cell_type": "code", "execution_count": 84, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "{1: 1, 3: 3, 2: 2}" ] }, "execution_count": 84, "metadata": {}, "output_type": "execute_result" } ], "source": [ "dct = {1:1}\n", "dct[3] = 3\n", "dct[2] = 2\n", "dct" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Python 3.7" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "### New `breakpoint()` function (PEP 553)\n", "\n", "Python 3.7 includes the new built-in breakpoint() function as an easy and consistent way to enter the Python debugger." ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a\n", "--Return--\n", "None\n", "> \u001b[1;32m\u001b[0m(2)\u001b[0;36m\u001b[1;34m()\u001b[0m\n", "\u001b[1;32m 1 \u001b[1;33m\u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"a\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[0m\u001b[1;32m----> 2 \u001b[1;33m\u001b[0mbreakpoint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[0m\u001b[1;32m 3 \u001b[1;33m\u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34m\"b\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", "\u001b[0m\n", "ipdb> c\n", "b\n" ] } ], "source": [ "print(\"a\")\n", "breakpoint()\n", "print(\"b\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Python 3.8" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Assignment expressions (PEP 572)\n", "\n", "There is new syntax `:=` that assigns values to variables as part of a larger expression. It is affectionately known as “the walrus operator” due to its resemblance to the eyes and tusks of a walrus." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In this example, the assignment expression helps avoid calling len() twice:" ] }, { "cell_type": "code", "execution_count": 93, "metadata": {}, "outputs": [], "source": [ "if (n := len(dct)) > 10:\n", " print(f\"List is too long ({n} elements, expected <= 10)\")" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Positional-only parameters (PEP 570)\n", "\n", "There is a new function parameter syntax `/` to indicate that some function parameters must be specified positionally and cannot be used as keyword arguments. " ] }, { "cell_type": "code", "execution_count": 95, "metadata": {}, "outputs": [], "source": [ "def f(a, b, /, c, d, *, e, f):\n", " print(a, b, c, d, e, f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Symbol `*` indicates Keyword-Only Arguments." ] }, { "cell_type": "code", "execution_count": 96, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10 20 30 40 50 60\n" ] } ], "source": [ "f(10, 20, 30, d=40, e=50, f=60)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "fragment" } }, "source": [ "Invalid calls\n", "```python\n", "f(10, b=20, c=30, d=40, e=50, f=60) # b cannot be a keyword argument\n", "f(10, 20, 30, 40, 50, f=60) # e must be a keyword argument\n", "```" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## f-strings support = for self-documenting expressions and debugging\n", "\n", "Added an = specifier to f-strings. An f-string such as f'{expr=}' will expand to the text of the expression, an equal sign, then the representation of the evaluated expression." ] }, { "cell_type": "code", "execution_count": 102, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"user='eric_idle' member_since=datetime.date(1975, 7, 31)\"" ] }, "execution_count": 102, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from datetime import date\n", "\n", "user = 'eric_idle'\n", "member_since = date(1975, 7, 31)\n", "f'{user=} {member_since=}'\n", "\"user='eric_idle' member_since=datetime.date(1975, 7, 31)\"" ] }, { "cell_type": "code", "execution_count": 103, "metadata": { "slideshow": { "slide_type": "fragment" } }, "outputs": [ { "data": { "text/plain": [ "'user=eric_idle delta.days=16,604'" ] }, "execution_count": 103, "metadata": {}, "output_type": "execute_result" } ], "source": [ "delta = date.today() - member_since\n", "f'{user=!s} {delta.days=:,d}'" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Python 3.9" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## String methods to remove prefixes and suffixes (PEP 616)" ] }, { "cell_type": "code", "execution_count": 106, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " from Python 3.9!\n", "Hello World from Python 3.9!\n", "Hello World from Python \n", "Hello World from Python 3.9!\n" ] } ], "source": [ "s = 'Hello World from Python 3.9!'\n", "print(s.removeprefix('Hello World')) # from Python 3.9!\n", "print(s.removeprefix('')) # Hello World from Python 3.9!\n", "\n", "print(s.removesuffix('3.9!')) # Hello World from Python\n", "print(s.removesuffix('Python')) # Hello World from Python 3.9!" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "# Python 3.10 (3.10.0a4 released January 13, 2021)" ] }, { "cell_type": "markdown", "metadata": { "slideshow": { "slide_type": "slide" } }, "source": [ "## Typing \n", "\n", "* PEP 563: Postponed Evaluation of Annotations Becomes Default\n", "* PEP 613: TypeAlias Annotation\n", "* PEP 604: New Type Union Operator\n", "\n", "### New Type Union Operator (PEP 604)\n", "A new type union operator was introduced which enables the syntax `X | Y`. " ] }, { "cell_type": "code", "execution_count": 109, "metadata": {}, "outputs": [], "source": [ "def square(number: Union[int, float]) -> Union[int, float]:\n", " return number ** 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "def square(number: int | float) -> int | float:\n", " return number ** 2\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "celltoolbar": "Slideshow", "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.1" } }, "nbformat": 4, "nbformat_minor": 2 }