Python3.8 has been released for almost a month, and it will be over a decade since the first version of Python3.0 was released. Many people are still using Python2.7 and want to migrate to the latest version but don’t know how to quickly learn the most Amazing methods. In this article, I will recommend that version 3.0 relies on the latest functions and syntax to help you stand out when reviewing code.

preface

Let’s start with a few points in time:

  • Python2.7 officially stops maintenance on January 1, 2020, more than a month away

  • Python3.8 was officially released on October 14, 2019, almost a month ago

As you can see from these two numbers, Python3 has been a long time coming, and the end of Python2.7 is getting closer. In the year since Python2.7 went out of maintenance, many good open source projects have stopped supporting 2.7. For example, NumPy will stop supporting Python2 in January; By the end of this year, Ipython, Cython, Pandas, and others will be discontinuing Python 2 support.

So, to answer the call, go with the flow. We are slowly migrating to Python3.X, so how can we quickly master the essence of python3. X? Let’s start with a few interesting new features or methods that have been added in various versions of Python 3 that make it easier to solve practical problems than traditional Python methods.

All of the examples were written in Python 3.7, and each feature example gives the lowest version of Python it needs to work properly.

Trend features

  1. Format string f-string (minimum Python version 3.6)

The topic “how to Format a string” is a syntax that every developer must learn when learning a new language. In Python, people usually prefer either [Format] or [%S] to Format the syntax.

print("My name is %s" % ('phithon')),print("My name is %(name)s" % {'name':'phithon'})
print("My name is {}".format("bob"))
print("My name is {name}".format(name="bob"))
Copy the code

In Python3.6, a new flexible way to format strings [f-string] was introduced. Code written using f-string with the same functionality as above looks like this

name="bob"
print(f"My name is {name}")
Copy the code

Comparing these methods of formatting strings, we can find that [F-string] inserts variables directly into placeholders are much more convenient and understandable than the common string Format methods [%S] or [Format]. Please refer to this blog post for a detailed explanation of formatting speed.

  1. Path management library Pathlib (Minimum Python version 3.4)

As you can see from the last feature, f-String is really powerful and beautiful, and when it comes to file paths, Python is following their philosophy that everything is an object, so they’ve created a path object library, which is an abstract library that deals with file paths. If you don’t know why you should use [Pathlib], see the following chicken stick blog post by Trey Hunner and its subsequent versions, where we compare the old and new Python implementations of the same case:

from glob import glob

file_contents = []
for filename in glob('**/*.py', recursive=True):
    with open(filename) as python_file:
        file_contents.append(python_file.read())
Copy the code
from pathlib import Path

file_contents = [
    path.read_text()
    for path in Path.cwd().rglob('*.py')
]s')
Copy the code

As shown above, you can read the contents of a file into a new list by read_text, which is syntactically and aesthetically better than using older versions of Python.

  1. Type hint Type hinting (minimum Python version 3.5)

There are many types of programming languages, and the contrast between statically compiled and dynamically interpreted languages is a hot topic in software engineering, and almost everyone has an opinion on it. In static languages, type labeling is undoubtedly both love-hate and love-hate. What I love is the speed of compilation, the accurate understanding of input parameter types of function methods in teamwork, and the extremely tedious labeling in Coding. However, tagging was introduced in Python3 and quickly gained popularity as a very team-friendly practice.

def print_yes_or_no(codition: str) -> bool:
  pass
Copy the code
  1. Enumeration (minimum Python version 3.4)

Enumerations are a feature that you’ll encounter when writing Java or C, and they save you a lot of time and make your code look better. In the old version of Python, we want to implement enumeration in various ways, “eight imfairy across the sea, each has his own magic”, giving full play to the dynamic language features of Python. Here are some examples:

# use type to create a class
def enum(**enums):
    return type('Enum', (), enums)
 
Numbers = enum(ONE=1, TWO=2, THREE='three')
# Numbers.ONE == 1, Numbers.TWO == 2 and Numbers.THREE == 'three'
Copy the code
# Use the type class to create an updated version of the class
def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    return type('Enum', (), enums)
 
Numbers = enum('ZERO'.'ONE'.'TWO')
# Numbers.ZERO == 0 and Numbers.ONE == 1
Copy the code
# there is a value-to-name mapping
def enum(*sequential, **named):
    enums = dict(zip(sequential, range(len(sequential))), **named)
    reverse = dict((value, key) for key, value in enums.iteritems())
    enums['reverse_mapping'] = reverse
    return type('Enum', (), enums)

# Numbers.reverse_mapping['three'] == 'THREE'
Copy the code
# more importantly, namedTuple implementation
from collections import namedtuple
def enum(*keys):
    return namedtuple('Enum', keys)(*keys)
 
MyEnum = enum('FOO'.'BAR'.'BAZ')
 
# alphanumeric mapping, like C/C++
def enum(*keys):
    return namedtuple('Enum', keys)(*range(len(keys)))
 
With dictionary mapping, you can map all types, not just numbers
def enum(**kwargs):
    return namedtuple('Enum', kwargs.keys())(*kwargs.values())
Copy the code

Now that Python3 has cleared your eyes, Python3.4 has introduced an easy way to write enumerations from the “Enum” class.

from enum import Enum, auto
class Monster(Enum):    
       ZOMBIE = auto()    
       WARRIOR = auto()    
       BEAR = auto()
print(Monster.ZOMBIE)
for i in Monster:
  print(i)
#Monster.ZOMBIE
#Monster.ZOMBIE
#Monster.WARRIOR
#Monster.BEAR
Copy the code

Above we can see that enumerations are collections of symbol names (members) bound to unique constant values. In enumerations, members can be compared by identity, and enumerations themselves can be traversed.

  1. Native LRU cache (minimum Python version 3.2)

Caching is a feature that everyone uses in development, and it can save a lot of time and money if we use it correctly. Many people who are beginning to learn Python decorators will implement a cached decorator to save Fibonacci computation time. Python 3 makes using the LRU (Least Recently used algorithm) cache very simple by using it as a decorator named “lru_cache”.

Here is a simple Fibonacci function that we know will be helped by caching because it performs the same work recursively many times.

import time
def fib(number: int) -> int:    
  if number == 0: 
    return 0    
  if number == 1: 
    return 1    
  return fib(number-1) + fib(number-2)
start = time.time()
fib(40)
print(f'Duration: {time.time() - start}s')
# Duration: 30.684099674224854 s
Copy the code

We saw that when we didn’t use the cache decorator we calculated a time of about 30 seconds, and now we can optimize it using “lru_cache” (this optimization technique is called “memoization”). With this optimization, we reduced the execution time from seconds to nanoseconds.

from functools import lru_cache
@lru_cache(maxsize=512)
def fib_memoization(number: int) -> int:    
  if number == 0: 
    return 0    
  if number == 1: 
    return 1    
  return fib_memoization(number-1) + fib_memoization(number-2)
start = time.time()
fib_memoization(40)
print(f'Duration: {time.time() - start}s')
# Duration: 6.866455078125 e-05 s
Copy the code

You can see how using the cache decorator is an expensive way to develop computational functions, and since the new version of Python3.8, lru_cache can now be used directly as a decorator rather than as a function that returns the decorator. So both are now supported:

@lru_cache
def f(x):
    ...

@lru_cache(maxsize=256)
def f(x):
    ...
Copy the code
  1. Extended iterable unpacking (minimum Python version 3.0)

Python unpacking is something we all knew when we were first learning Python, and it would be cool if we learned a lot about it. So what is unpacking an extension? We can learn more about pep3132, for example:

The print function in # Python 3.4 does not allow multiple * operations
>>> print(* [1, 2, 3], [3, 4]) File"<stdin>", line 1
    print(* [1, 2, 3], [3, 4]) ^ SyntaxError: invalid syntax > > >Copy the code
# take a look at python3.5 and above
Any number of unpacking operations can be used
>>> print(*[1], *[2], 3) 1 2 3 >>> *range(4), 4 (0, 1, 2, 3, 4) >>> [*range(4), 4] [0, 1, 2, 3, 4] >>> {*range(4), 4} {0, 1, 2, 3, 4} > > > {'x'* * {: 1,'y': {2}}'x': 1, 'y'2} :Copy the code

As you can see, unpacking is one of the most popular ways to unpack in Python.

  1. Data Class decorator (minimum Python version 3.7)

Python 3.7 introduced a new feature called Data Class, which greatly simplifies the amount of code required to define class objects. Decorating the design of aclass with the @dataclass decorator can be used to reduce the use of boilerplate code because the decorator automatically generates special methods such as “__init__ ()” and “__repr () __”. In the official documentation, they are described as “mutable named tuples with default values”.

from dataclasses import dataclass

@dataclass
class DataClassCard:
    rank: str
    suit: str


# create instance
queen_of_hearts = DataClassCard('Q'.'Hearts')
print(queen_of_hearts.rank)
print(queen_of_hearts)
print(queen_of_hearts == DataClassCard('Q'.'Hearts'))
#Q
#DataClassCard(rank='Q', suit='Hearts')
#True
Copy the code

A regular class would look something like this in Python syntax prior to 3.7

class RegularCard
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit
queen_of_hearts = RegularCard('Q'.'Hearts')
print(queen_of_hearts.rank)
print(queen_of_hearts)
print(queen_of_hearts == RegularCard('Q'.'Hearts'))
#'Q'
#<__main__.RegularCard object at 0x7fb6eee35d30>
#False 
Copy the code

It doesn’t take much more code, but it’s easy to see that rank and suit are repeated three times in order to initialize, just to initialize an object. In addition, if you try to use the RegularCard class, you will notice that the representation of objects is not very descriptive and that existing classes are not comparable with newly declared classes. Because each declaration uses a new memory address, “==” not only compares the information stored by the class, but also compares whether the memory address is the same.

Dataclass also gives us more useful encapsulation at the bottom. By default, dataclass implements the __repr__ method, which provides a nice string representation; The __eq__ method is also used to do basic object comparisons. If RegularCard wants to implement the above functions, it needs to write a lot of declarations, and the amount of code is scary.

class RegularCard(object):
    def __init__(self, rank, suit):
        self.rank = rank
        self.suit = suit

    def __repr__(self):
        Print the information for the class
        return (f'{self.__class__.__name__}'  
                f'(rank={self.rank! r}, suit={self.suit! r})')  
         # Try turning the "! Remove r "or change the r to s or A, and see what happens to the output
         #conversion character: expected 's', 'r', or 'a'

    def __eq__(self, other):
        # can compare classes to be the same (regardless of memory address)
        if other.__class__ is not self.__class__:
            return NotImplemented
        return (self.rank, self.suit) == (other.rank, other.suit)
Copy the code
  1. Implicit namespace package (minimum Python version 3.3)

One way to organize Python code files is to wrap them in a package (containing a folder called “init.py”). The following is an example provided by the official documentation.

sound/  Top-level package      
  __init__.py  Initialize the sound package      
  formats/ Subpackage for file format conversions              
    __init__.py              
    wavread.py              
    wavwrite.py              
    aiffread.py              
    aiffwrite.py              
    auread.py              
    auwrite.py              .
    ..      
  effects/  Subpackage for sound effects              
    __init__.py              
    echo.py              
    surround.py              
    reverse.py              
    ...      
  filters/  Subpackage for filters             
    __init__.py              
    equalizer.py              
    vocoder.py              
    karaoke.py              
    ...

Copy the code

In Python 2, each of the above folders must contain the “init.py” file that converts the folder into a Python package. In Python 3, with the introduction of the implicit namespace package, these files are no longer required.

sound/ Top-level package      
  __init__.py  Initialize the sound package      
  formats/  Subpackage for file format conversions 
    wavread.py              
    wavwrite.py              
    aiffread.py              
    aiffwrite.py              
    auread.py              
    auwrite.py              
    ...      
  effects/  Subpackage for sound effects              
    echo.py              
    surround.py              
    reverse.py              
    ...      
  filters/ Subpackage for filters              
    equalizer.py              
    vocoder.py              
    karaoke.py              
    ...
Copy the code

As some have said, the work is not as simple as this article suggests. The official document “PEP 420 Specification” states that regular packages still require “init.py”, and removing it from a folder turns that folder into a local namespace package, which brings some additional limitations. The official documentation for the local namespace package gives a good example and clearly points out all the limitations.

conclusion

There are a few cool features listed above that may not be all there is to explore for yourself and your team. This article is just to show you some fun new Python features that will help you write more Pythonic code.

Main introduction

I have worked in a second-tier factory for the past two years, and now I am moving bricks in a start-up company

The direction of contact is crawler and cloud native architecture

I have rich experience in reverse climbing and cloud primary secondary development

Others, such as data analytics and hacking growth, have also dabbled

I have done business sharing with more than 100 people and held training courses for many times

At present, he is also CSDN blog expert and Huawei cloud sharing expert

Highlights from the past

Only 3 minutes to shock |! Fast deployment of personal Docker cloud platform

In-depth understanding of Python’s TLS mechanism and threading.local ()

Why don’t I suggest you use Python3.7.3?

Next generation container architecture is out, where is Docker going? Check out the 6 questions and 6 answers here!!

You can get the advanced reverse teaching video of crawler and multi-platform Chinese data set by replying to “private data” in the public account