Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Should We Return to Python 2?

Should We Return to Python 2?

No.

Miroslav Šedivý

April 23, 2021
Tweet

More Decks by Miroslav Šedivý

Other Decks in Programming

Transcript

  1. Which Python version to support? | | | | |

    | | | | 2.7 ============| | | | | | | | 3.4 === | | | | | | | | 3.5 ===================== | | | | | | | 3.6 ====================================| | | | | | 3.7 ##################==================================== | | | | 3.8 | ##################========================================== | | | 3.9 | | ####################========================================= | | 3.10 | | | ####################========================================= | 3.11 | | | | ####################========================================= 3.12 | | | | | ####################=============================→ 3.13 | | | | | | ####################=================→ π-py | | | | | | | ####################=====→ 3.15 | | | | | | | | #############→ | | | | | | | | | +-----------+-----------+--X--------+-----------+-----------+-----------+-----------+-----------+---- 2019 2020 2021 2022 2023 2024 2025 2026 2027   eumiro 5
  2. Which Python version to support? | | | | |

    | | | | 2.7 ============| | | | | | | | 3.4 === | | | | | | | | 3.5 ===================== | | | | | | | 3.6 ====================================| | | | | | 3.7 ##################==================================== | | | | 3.8 | ##################========================================== | | | 3.9 | | ####################========================================= | | 3.10 | | | ####################========================================= | 3.11 | | | | ####################========================================= 3.12 | | | | | ####################=============================→ 3.13 | | | | | | ####################=================→ π-py | | | | | | | ####################=====→ 3.15 | | | | | | | | #############→ | | | | | | | | | +-----------+-----------+--X--------+-----------+-----------+-----------+-----------+-----------+---- 2019 2020 2021 2022 2023 2024 2025 2026 2027 an application: 3.9 a library: 3.6–3.9   eumiro 5
  3. Your code runs in Python 3? print … d.iterkeys() d.itervalues()

    d.iteritems() xrange(…)   eumiro 6
  4. Your code runs in Python 3? print … d.iterkeys() d.itervalues()

    d.iteritems() xrange(…) six if sys.version_info > (3, 0) try: import x except ImportError: import y   eumiro 6
  5. Make sure it runs ├── .github │ └── workflows │

    └── ci.yml ├── setup.py ├── src │ └── project │ └── … ├── tests │ └── … └── tox.ini   eumiro 7
  6. Make sure it runs ├── .github │ └── workflows │

    └── ci.yml ├── setup.py ├── src │ └── project │ └── … ├── tests │ └── … └── tox.ini [tox] envlist = py36,py37,py38,py39 [testenv] deps = pytest commands = python -m pytest {posargs}   eumiro 7
  7. name: CI on: [push, pull_request] jobs: build: runs-on: ubuntu-latest strategy:

    matrix: python-version: [3.6, 3.7, 3.8, 3.9] steps: - uses: actions/checkout@v1 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v2 with: python-version: ${{ matrix.python-version }} - name: Install dependencies run: | python -m pip install --upgrade pip pip install tox - name: Test with tox run: tox   eumiro 8
  8. https://github.com/jugmac00/python-version-cheat-sheet python 3.6 introduction of type annotations for variables (PEP

    526) f-strings (PEP 498) introduction of underscores in numeric literals, e.g. 1_000 (PEP 515) python 3.7 postponed evaluation of annotations via from __future__ import annotations (PEP 563) sort order of dicts is now guaranteed introduction of breakpoint, additionally to import pdb;pdb.set_trace() (PEP 553) introduction of data classes (PEP 557) python 3.8 introduction of the walrus operator (PEP 572) python 3.9 builtin generic types, that means you can use list and dict for type annotations, instead of importing e.g. from typing import List (PEP 585)   eumiro 9
  9. # coding: utf-8 (utf-8 is default) class Dummy(object): class Dummy:

    super(Inherited, self).func() super().func()   eumiro 10
  10. # coding: utf-8 (utf-8 is default) class Dummy(object): class Dummy:

    super(Inherited, self).func() super().func() u'hello world' "hello world"   eumiro 10
  11. # coding: utf-8 (utf-8 is default) class Dummy(object): class Dummy:

    super(Inherited, self).func() super().func() u'hello world' "hello world" pip install pyupgrade   eumiro 10
  12. # coding: utf-8 (utf-8 is default) class Dummy(object): class Dummy:

    super(Inherited, self).func() super().func() u'hello world' "hello world" pip install pyupgrade pyupgrade --py36-plus **/*.py   eumiro 10
  13. # coding: utf-8 (utf-8 is default) class Dummy(object): class Dummy:

    super(Inherited, self).func() super().func() u'hello world' "hello world" pip install pyupgrade pyupgrade --py36-plus **/*.py Make sure it looks good: black/blue, yapf flake8, pylint   eumiro 10
  14. String formatting 'Field %s contains value %r' % (field, value)

    'Field {} contains value {!r}'.format(field, value) f'Field {field} contains value {value!r}'   eumiro 11
  15. String formatting 'Field %s contains value %r' % (field, value)

    'Field {} contains value {!r}'.format(field, value) f'Field {field} contains value {value!r}' log.info('Field %s contains value %r', field, value)   eumiro 11
  16. String formatting 'Field %s contains value %r' % (field, value)

    'Field {} contains value {!r}'.format(field, value) f'Field {field} contains value {value!r}' log.info('Field %s contains value %r', field, value) # -*- coding: latin-1 -*- func("���") func("\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd")   eumiro 11
  17. String formatting 'Field %s contains value %r' % (field, value)

    'Field {} contains value {!r}'.format(field, value) f'Field {field} contains value {value!r}' log.info('Field %s contains value %r', field, value) # -*- coding: latin-1 -*- func("���") func("\xef\xbf\xbd\xef\xbf\xbd\xef\xbf\xbd") "Šedivý" "\u0160ediv\00fd" "\N{LATIN CAPITAL LETTER S WITH CARON}ediv\N{LATIN SMALL LETTER Y WITH ACUTE}"   eumiro 11
  18. Numbers int(math.floor(x)) int(math.ceil(x)) int(round(x)) # Python 2 >>> sys.maxint 9_223_372_036_854_775_807

    # Python 2+3 >>> sys.float_info.max 1.7976931348623157e+308   eumiro 12
  19. >>> vals = [3, 3, 4, 4] >>> sum(vals) /

    len(vals) 3   eumiro 13
  20. >>> vals = [3, 3, 4, 4] >>> sum(vals) /

    len(vals) 3 >>> float(sum(vals)) / len(vals) >>> sum(vals) / float(len(vals)) >>> 1.0 * sum(vals) / len(vals) 3.5   eumiro 13
  21. >>> vals = [3, 3, 4, 4] >>> sum(vals) /

    len(vals) 3 >>> float(sum(vals)) / len(vals) >>> sum(vals) / float(len(vals)) >>> 1.0 * sum(vals) / len(vals) 3.5 >>> from __future__ import division >>> sum(vals) / len(vals) 3.5   eumiro 13
  22. >>> vals = [3, 3, 4, 4] >>> sum(vals) /

    len(vals) 3 >>> float(sum(vals)) / len(vals) >>> sum(vals) / float(len(vals)) >>> 1.0 * sum(vals) / len(vals) 3.5 >>> from __future__ import division >>> sum(vals) / len(vals) 3.5 >>> sum(vals) / len(vals) 3.5   eumiro 13
  23. “God made the integers; all else is the work of

    man.” — Leopold Kronecker   eumiro 14
  24. “God made the integers; all else is the work of

    man.” — Leopold Kronecker >>> 9_007_199_254_740_993.0 9_007_199_254_740_992.0   eumiro 14
  25. “God made the integers; all else is the work of

    man.” — Leopold Kronecker >>> 9_007_199_254_740_993.0 9_007_199_254_740_992.0 number of nanoseconds in 105 days   eumiro 14
  26. “God made the integers; all else is the work of

    man.” — Leopold Kronecker >>> 9_007_199_254_740_993.0 9_007_199_254_740_992.0 number of nanoseconds in 105 days >>> 0.1 + 0.1 + 0.1 0.30000000000000004   eumiro 14
  27. “God made the integers; all else is the work of

    man.” — Leopold Kronecker >>> 9_007_199_254_740_993.0 9_007_199_254_740_992.0 number of nanoseconds in 105 days >>> 0.1 + 0.1 + 0.1 0.30000000000000004 >>> sum(0.3 for _ in range(1_000_000)) # 50ms 299999.99999434233   eumiro 14
  28. “God made the integers; all else is the work of

    man.” — Leopold Kronecker >>> 9_007_199_254_740_993.0 9_007_199_254_740_992.0 number of nanoseconds in 105 days >>> 0.1 + 0.1 + 0.1 0.30000000000000004 >>> sum(0.3 for _ in range(1_000_000)) # 50ms 299999.99999434233 >>> sum(decimal.Decimal('0.3') for _ in range(1_000_000)) # 350ms Decimal('300000.0')   eumiro 14
  29. “God made the integers; all else is the work of

    man.” — Leopold Kronecker >>> 9_007_199_254_740_993.0 9_007_199_254_740_992.0 number of nanoseconds in 105 days >>> 0.1 + 0.1 + 0.1 0.30000000000000004 >>> sum(0.3 for _ in range(1_000_000)) # 50ms 299999.99999434233 >>> sum(decimal.Decimal('0.3') for _ in range(1_000_000)) # 350ms Decimal('300000.0') >>> sum(fractions.Fraction(3, 10) for _ in range(1_000_000)) # 3s Fraction(300000, 1)   eumiro 14
  30. >>> hours = minutes / 60.0 hours = minutes /

    60 >>> avg = (a + b) / 2.0 avg = (a + b) / 2   eumiro 15
  31. >>> hours = minutes / 60.0 hours = minutes /

    60 >>> avg = (a + b) / 2.0 avg = (a + b) / 2 >>> math.floor((a + b) / 2) >>> int((a + b) / 2) >>> (a + b) // 2   eumiro 15
  32. Percentages >>> perc = 1 / 7 * 100 >>>

    f'{perc:.1f}%' 14.3%   eumiro 17
  33. Percentages >>> perc = 1 / 7 * 100 >>>

    f'{perc:.1f}%' 14.3% >>> ratio = 1 / 7 >>> f'{ratio:.1%}' 14.3%   eumiro 17
  34. Numeric literals nanoseconds = seconds * 10e9 nanoseconds = seconds

    * 1000000000 nanoseconds = seconds * 1_000_000_000   eumiro 18
  35. Numeric literals nanoseconds = seconds * 10e9 nanoseconds = seconds

    * 1000000000 nanoseconds = seconds * 1_000_000_000 nanoseconds = seconds * 10**9   eumiro 18
  36. pathlib.Path parent = '/data' for fn in os.listdir(parent): stem, ext

    = os.path.splitext(fn) if ext == '.csv': fname = os.path.join(parent, fn) with open(fname, 'rb') as f: data = f.read() process(data)   eumiro 19
  37. pathlib.Path parent = '/data' for fn in os.listdir(parent): stem, ext

    = os.path.splitext(fn) if ext == '.csv': fname = os.path.join(parent, fn) with open(fname, 'rb') as f: data = f.read() process(data) for path in Path('/data').glob('*.csv'): process(path.read_bytes())   eumiro 19
  38. pathlib.Path parent = '/data' for fn in os.listdir(parent): stem, ext

    = os.path.splitext(fn) if ext == '.csv': fname = os.path.join(parent, fn) with open(fname, 'rb') as f: data = f.read() process(data) for path in Path('/data').glob('*.csv'): process(path.read_bytes()) if path.exists(): path.unlink() # and since Python 3.8: path.unlink(missing_ok=False)   eumiro 19
  39. pathlib.Path and pytest def test_something(self): file = tempfile.NamedTemporaryFile(mode='w', delete=False) self.assertTrue(process(file))

    os.unlink(file) def test_something(tmp_path): assert process(tmp_path / 'something.dat')   eumiro 20
  40. pathlib.Path and pytest def test_something(self): file = tempfile.NamedTemporaryFile(mode='w', delete=False) self.assertTrue(process(file))

    os.unlink(file) def test_something(tmp_path): assert process(tmp_path / 'something.dat') /tmp/pytest-of-miro/pytest-1/test_something/something.dat   eumiro 20
  41. datetime >>> dt = datetime.datetime(1970, 1, 1) >>> calendar.timegm(dt.utctimetuple()) 0

    >>> dt = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc) >>> dt.timestamp() 0.0   eumiro 21
  42. datetime >>> dt = datetime.datetime(1970, 1, 1) >>> calendar.timegm(dt.utctimetuple()) 0

    >>> dt = datetime.datetime(1970, 1, 1, tzinfo=datetime.timezone.utc) >>> dt.timestamp() 0.0 try: import zoneinfo except ImportError: from backports import zoneinfo now = datetime.datetime.now(zoneinfo.ZoneInfo('Europe/Berlin'))   eumiro 21
  43. time.time() >>> start = time.time() >>> run_expensive_operation() >>> end =

    time.time() >>> end - start >>> time.perf_counter()   eumiro 22
  44. time.time() >>> start = time.time() >>> run_expensive_operation() >>> end =

    time.time() >>> end - start >>> time.perf_counter() >>> time.process_time()   eumiro 22
  45. Should We Return to Python 2? Here's the plan: When

    someone uses a feature you don't understand, simply shoot them. This is easier than learning something new, and before too long the only living coders will be writing in an easily understood, tiny subset of Python 0.9.6 . — Tim Peters, 2002 24
  46. Should We Return to Python 2? Here's the plan: When

    someone uses a feature you don't understand, simply shoot them. This is easier than learning something new, and before too long the only living coders will be writing in an easily understood, tiny subset of Python 0.9.6 . — Tim Peters, 2002 Miroslav Šedivý   eumiro 24