Slice infinite generators with this Python 3.7 feature | Opensource.com

Slice infinite generators with this Python 3.7 feature

Learn more about this and two other underutilized but still useful Python features.

Hands on a keyboard with a Python book
Image by : 
WOCinTech Chat. Modified by Opensource.com. CC BY-SA 4.0
x

Subscribe now

Get the highlights in your inbox every week.

This is the eighth in a series of articles about features that first appeared in a version of Python 3.x. Python 3.7 was first released in 2018, and even though it has been out for a few years, many of the features it introduced are underused and pretty cool. Here are three of them.

Postponed evaluation of annotations

In Python 3.7, as long as the right __future__ flags are activated, annotations are not evaluated during runtime:

from __future__ import annotations

def another_brick(wall: List[Brick], brick: Brick) -> Education:
    pass
another_brick.__annotations__
    {'wall': 'List[Brick]', 'brick': 'Brick', 'return': 'Education'}

This allows recursive types (classes that refer to themselves) and other fun things. However, it means that if you want to do your own type analysis, you need to use ast explictly:

import ast
raw_type = another_brick.__annotations__['wall']
[parsed_type] = ast.parse(raw_type).body
subscript = parsed_type.value
f"{subscript.value.id}[{subscript.slice.id}]"
    'List[Brick]'

itertools.islice supports __index__

Sequence slices in Python have long accepted all kinds of int-like objects (objects that have __index__()) as valid slice parts. However, it wasn't until Python 3.7 that itertools.islice, the only way in core Python to slice infinite generators, gained this support.

For example, now it is possible to slice infinite generators by numpy.short-sized integers:

import numpy
short_1 = numpy.short(1)
short_3 = numpy.short(3)
short_1, type(short_1)
    (1, numpy.int16)
import itertools
list(itertools.islice(itertools.count(), short_1, short_3))
    [1, 2]

functools.singledispatch() annotation registration

If you thought singledispatch couldn't get any cooler, you were wrong. Now it is possible to register based on annotations:

import attr
import math
from functools import singledispatch

@attr.s(auto_attribs=True, frozen=True)
class Circle:
    radius: float
       
@attr.s(auto_attribs=True, frozen=True)
class Square:
    side: float

@singledispatch
def get_area(shape):
    raise NotImplementedError("cannot calculate area for unknown shape",
                              shape)

@get_area.register
def _get_area_square(shape: Square):
    return shape.side ** 2

@get_area.register
def _get_area_circle(shape: Circle):
    return math.pi * (shape.radius ** 2)

get_area(Circle(1)), get_area(Square(1))
    (3.141592653589793, 1)

Welcome to 2017

Python 3.7 was released about four years ago, but some of the features that first showed up in this release are cool—and underused. Add them to your toolkit if you haven't already.

Hands on a keyboard with a Python book

Explore some of the underutilized but still useful Python features.
Python programming language logo with question marks

Explore some of the underutilized but still useful Python features.
Business woman on laptop sitting in front of window

Explore some of the underutilized but still useful Python features.
Coding on a computer

Explore exception handling and other underutilized but still useful Python features.
old school calculator

Plus explore some of the underutilized but still useful Python features.
Hacker code matrix

Explore some of the underutilized but still useful Python features.
Computer screen with files or windows open

Explore os.fspath and two other underutilized but still useful Python features.
Hands on a keyboard with a Python book

Learn more about this and two other underutilized but still useful Python features.

Topics

About the author

Moshe sitting down, head slightly to the side. His t-shirt has Guardians of the Galaxy silhoutes against a background of sound visualization bars.
Moshe Zadka - Moshe has been involved in the Linux community since 1998, helping in Linux "installation parties". He has been programming Python since 1999, and has contributed to the core Python interpreter. Moshe has been a DevOps/SRE since before those terms existed, caring deeply about software reliability, build reproducibility and other such things. He has worked in companies as small as three people and as big as tens of thousands -- usually some place around where software meets system administration...