Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use the new features of Python3.8

2025-02-14 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)05/31 Report--

This article mainly introduces the relevant knowledge of how to use the new features of Python3.8, the content is detailed and easy to understand, the operation is simple and fast, and it has a certain reference value. I believe you will gain something after reading this article on how to use the new features of Python3.8. Let's take a look at it.

1. Assignment expression (Assignment expressions)

The introduction of assignment expressions is arguably the biggest change in Python3.8. Note that the new symbol (: =) is now used, which is shaped like the side tooth of a walrus, also known as the "walrus operator". An assignment expression can assign a value in a unified expression and return a value, such as the following code, which assigns a value to a variable and prints the value

> walrus = False > print (walrus) FalsePython3.8, you can use the walrus operator to merge the above two statements into one sentence > print (walrus: = True) True

The assignment expression can assign True to walrus and print this value directly. There must be (: =), otherwise the expression cannot be executed properly, with the new assignment expression symbol, it is not only easier to construct, but also can convey the intention of the code more clearly.

For example, in the while loop, it shows the advantage of (: =).

Inputs = list () current = input ("Write something:") while current! = "quit": inputs.append (current) current = input ("Write something:")

The above code is not good enough to keep repeating the input statement and needs to be added to the current list in some way, and then after executing the following code, a better solution is to set up an infinite while loop and then stop the loop with break

Inputs = list () while True: current = input ("Write something:") if current = = "quit": break inputs.append (current)

This code is equivalent to the above code, but if you use an assignment expression, you can further simplify the loop:

Inputs = list () while (current: = input ("Write something:")! = "quit": inputs.append (current)

Now the code is more simplified, but the readability becomes worse, so you need to judge by yourself if you want to use the method of assignment expression.

The built-in function float () can be used to convert text strings and numeric types into float objects, such as the following code

> float ("3.8") 3.8 > help (float) class float (object) | float (xylene 0, /) | | Convert a string or number to a floating point number, if possible. What is the meaning of (/) in float (/)? For a discussion of this section, please refer to the following documentation, which is not our focus in today's content: PEP 457-Notation For Positional-Only Parameters https://www.python.org/dev/peps/pep-0457/.

It turns out that although float () calls the parameter x, its name is not allowed

> float (x = "3.8") Traceback (most recent call last): File "", line 1, in TypeError: float () takes no keyword arguments

When using float (), only parameters are allowed to be specified by location, not keyword arguments. Before Python3.8, this type of positional-only parameters only applied to built-in parameters, and in our own defined functions, there was no simple way to specify parameters as positional-only parameters.

> def incr (x): Return x + 1... > > incr (3.8) 4.8 > incr (x = 3.8) 4.8

The above code uses * args to simulate only position parameters, but it is not flexible enough and not easy to read. In Python3.8, you can use / to indicate that you must override incr () to receive position parameters through only the parameters before the position parameters:

> def incr (x, /): Return x + 1... > > incr (3.88.8) Traceback (most recent call last): File ", line 1, in TypeError: incr () got some positional-only arguments passed as keyword arguments:'x'

By adding / after x, you can specify x as a position-only parameter. General parameters are used in conjunction with position-only parameters to put general parameters after /:

Def greet (name, /, greeting= "Hello"):... Return f "{greeting}, {name}"... > > greet ("recent ukasz") 'Hello, ukasz' > greet ("awesome ukasz", greeting= "Awesome job")' Awesome job, greet (name= "awesome ukasz", greeting= "Awesome job") Traceback (most recent call last): File ", line 1, in TypeError: greet () got some positional-only arguments passed as keyword arguments: 'name'

In greet (), / is placed between name and greeting, indicating that name is a positional parameter only, and greeting is a regular parameter that can be passed by position or keyword.

You may think that the readability of only location parameters does not seem good, but after using it, you will find that in many cases, only location parameters can optimize our code. In addition, using location-only functions has the advantage of making it easier to ReFactor a function without having to worry about the impact on other code when changing the name of the function. Only the position function also well complements the keyword-only parameters. You can use * to specify keyword-only parameters:

> def to_fahrenheit (*, celsius): Return 32 + celsius * 9 / 5... > > to_fahrenheit (40) Traceback (most recent call last): File ", line 1, in TypeError: to_fahrenheit 0 positional arguments but 1 was given > to_fahrenheit (celsius=40) 104.0

In the previous code, celsius is a keyword parameter only.

You can also combine position-only, regular, and keyword-only parameters * by separating them in / and order. For example, in the following code, text is a positional parameter, border is a regular parameter (the value is the default), and width is a keyword parameter (the value is the default):

Def headline (text, /, border= "♦", *, width=50):. Return f "{text}" .center (width, border)... text is a positional parameter only, so you cannot use the keyword text: > > headline ("Positional-only Arguments") '♦ Positional-only Arguments ♦' > headline (text= "This doesn't work!") Traceback (most recent call last): File "", line 1, in TypeError: headline () got some positional-only arguments passed as keyword arguments: 'text'border can either use keywords You can also specify: > headline ("Python 3.8", "=")'= Python 3.8 ='> headline ("Real Python", border= ":")': Real Python:'

Finally, width must be specified with a keyword:

> headline ("Python", "?", width=38)'? Python?'> > headline ("Python", "?", 38) Traceback (most recent call last): File ", line 1, in TypeError: headline 1 to 2 positional arguments but 3 were given

More detailed types

At this point, the type system of Python is quite mature. However, in Python 3.8, some new features have been added to typing to allow more precise typing:

Text type

Typing dictionary

Final object

Agreement

Python supports optional type hints, usually as comments on your code:

Def double (number: float)-> float: return 2 * number

In this example, the number should be a floating point number, and the double () function should also return a floating point number. However, Python treats these comments as prompts. They are not enforced at run time:

> double (3.14) 6.28 > double ("I'm not a float") "I'm not a floatI'm not a float"

Double () takes "I'm not a floating point number" as a parameter, even if it's not a floating point number. Some libraries can use types at run time, but this is not the primary use case for the Python type system.

Instead, type hints allow the static type checker to type the Python code without actually running the script. This is reminiscent of compiler-caught type errors in other languages such as Java,Rust and Crystal. In addition, type hints can be used as documentation for your code, making it easier to read and improving autocompletion in IDE.

Note: there are several static type checkers available, including Pyright,Pytype and Pyre. Mypy is used in this article. You can install Mypy from PyPI using pip:

In a sense, Mypy is a reference implementation of the Python type checker and was developed by Dropbox under the leadership of Jukka Lehtasalo. Guido van Rossum, the creator of Python, is a member of the Mypy team.

Python 3.8 has been accepted and contains four new PEP for type checking, each with short examples.

PEP 586 introduces text types. The text type is a bit special, it represents one or more specific values. One use case for literal types is the ability to precisely add types when a specific behavior is described using string parameters. The following is an example:

# draw_line.py def draw_line (direction: str)-> None: if direction = = "horizontal":. # Draw horizontal line elif direction = = "vertical":... # Draw vertical line else: raise ValueError (f "invalid direction {directionaccounr}") draw_line ("up")

The program will pass the static type checker, even if "up" is an invalid direction. The type checker only checks whether "up" is a string. In this case, the direction must be either the text string "horizontal" or the text string "vertical". With text types, you can do this completely:

Because you can expose the allowable value of direction to the type checker, you can now get a warning about the error:

$mypy draw_line.py draw_line.py:15: error: Argument 1 to "draw_line" has incompatible type "Literal ['up']"; expected "Union [Literal [' horizontal'], Literal ['vertical']]" Found 1 error in 1 file (checked 1 source file)

The basic syntax is Literal []. For example, Literal [38] represents a text value of 38. You can use Union to represent one of several text values:

Since this is a fairly common use case, you can (and should) use the simpler notation Literal ["horizontal", "vertical"]. When you add a type to draw_line (), you already use the latter. If you take a closer look at the output of Mypy above, you will find that it internally converts a simpler representation to a Union representation.

In some cases, the type of return value of a function depends on the input parameters. One example is open (), which returns a text string or byte array based on the value of mode. This can be handled by overloading.

The following example shows the flow of a calculator that returns the answer as a positive number (38) or Roman numeral (XXXVIII):

# calculator.py from typing import Union ARABIC_TO_ROMAN = [(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"), (50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5 "V"), (4, "IV"), (1, "I")] def _ convert_to_roman_numeral (number: int)-> str: "Convert number to a roman numeral string" result = list () for arabic, roman in ARABIC_TO_ROMAN: count, number = divmod (number, arabic) result.append (roman * count) return ".join (result) def add (num_1: int, num_2: int To_roman: bool = True)-> Union [str, int]: "Add two numbers" result = num_1 + num_2 if to_roman: return _ convert_to_roman_numeral (result) else: return result

The code has the correct type hint: the result of add () will be str or int. However, this code is usually called with true or False as the value of to_roman, in which case you want the type checker to infer exactly whether to return str or int. This can be done by using Literal and @ overload:

# calculator.py from typing import Literal, overload, Union ARABIC_TO_ROMAN = [(1000, "M"), (900, "CM"), (500, "D"), (400, "CD"), (100, "C"), (90, "XC"), (50, "L"), (40, "XL"), (10, "X"), (9, "IX"), (5 "V"), (4, "IV"), (1, "I")] def _ convert_to_roman_numeral (number: int)-> str: "Convert number to a roman numeral string" result = list () for arabic, roman in ARABIC_TO_ROMAN: count, number = divmod (number, arabic) result.append (roman * count) return ".join (result) @ overload def add (num_1: int, num_2: int) To_roman: Literal [True])-> str:... @ overload def add (num_1: int, num_2: int, to_roman: Literal [False])-> int:. Def add (num_1: int, num_2: int, to_roman: bool = True)-> Union [str, int]: "" Add two numbers "result = num_1 + num_2 if to_roman: return _ convert_to_roman_numeral (result) else: return result

The added @ overload signature will help your type checker infer str or int based on the literal value of to_roman. Note that the ellipsis (...) is the literal part of the code. They represent the functional body in the overloaded signature.

As a supplement to Literal, PEP 591 introduces Final. This qualifier states that variables or attributes should not be reassigned, redefined, or overridden. The following is a typing error:

From typing import Final ID: Final = 1... ID + = 1

Mypy will highlight the line ID + = 1, and note that you cannot assign it to the final name "ID". This ensures that the constant values in the code never change.

In addition, there is an @ final decorator that you can apply to classes and methods. Classes decorated with @ final cannot be subclassed, and @ final methods cannot be overridden by subclasses:

From typing import final @ final class Base:... Class Sub (Base):.

Mypy will mark this example with an error message that cannot be inherited from the final class "Base". For more information about Final and @ final, see PEP 591.

The third PEP that supports more specific type hints is PEP 589, which introduces TypedDict. You can use symbols similar to typed NamedTuple to specify the types of keys and values in dictionaries.

Traditionally, dictionaries is annotated using Dict. The problem is that this allows only one type key and one type value, which usually results in comments such as Dict [str,Any]. For example, a dictionaries that registers Python version information:

The value corresponding to version is a string, while release_year is an integer. This cannot be accurately expressed in Dict. With the new TypedDict, you can do the following:

From typing import TypedDict class PythonVersion (TypedDict): version: str release_year: int py38 = PythonVersion (version= "3.8", release_year=2019

The type checker will then be able to infer that the type of py38 ["version"] is str and that py38 ["release_year"] is an int value. At run time, TypedDict is a regular dict and type hints are ignored as usual. You can also use TypedDict purely as comments:

Mypy will tell you that any value is of the wrong type, or that you are using an undeclared key. See PEP 589 for more examples.

Mypy has supported the protocol for some time. However, official support will not be officially available until May 2019.

Protocol is a way of canonical Python support for duck types:

When I see a bird walking like a duck, swimming like a duck and quacking like a duck, I call it a duck.

Duck types allow you to read .name on any object that has a .name property, for example, without really caring about the type of the object. Supporting a type system seems counterintuitive. Through structural subtype conversion, it is still possible to understand the type of duck.

For example, you can define a protocol called Named that identifies all objects with a .name attribute:

From typing import Protocol class Named (Protocol): name: str def greet (obj: Named)-> None: print (f "Hi {obj.name}"

Here, greet () can accept any object as long as it defines the .name attribute. For more information about the protocol, see the PEP 544 and Mypy documentation.

Use f strings for easier debugging

The f string was introduced in Python 3.6and has become very popular. They are probably the most common reason why Python libraries are only supported on version 3.6 and later. The f string is the formatted string text. You can identify it by leading f:

> style = "formatted" > f "This is a {style} string" 'This is a formatted string'

When using an f string, you can enclose variables or even expressions in curly braces. They are then evaluated at run time and included in a string. An f string can contain multiple expressions:

The format specifier is also used in the final expression {math.pi * r * rbure.2f}. Format specifiers and expressions are separated by colons.

.2f indicates that the area is formatted as a floating point number with 2 decimals. The format specifier is the same as .format (). For a complete list of supported format specifiers, see the official documentation.

Official document

Https://docs.python.org/3/library/string.html#format-specification-mini-language

In Python 3.8, you can use assignment expressions in f strings. Just be sure to enclose the assignment expression in parentheses:

> import math > r = 3.8 > > f "Diameter {(diam: = 2 * r)} gives circumference {math.pi * diam:.2f}" 'Diameter 7.6 gives circumference 23.88'

However, the real f-news in Python 3.8is the new debug specifier. Now, you can add = to the end of the expression, which prints both the expression and its value:

> python=3.8 > f "{python=}" 'python=3.8'

This is a simple method and is usually most useful when working interactively or adding print statements to debug scripts. In earlier versions of Python, you had to spell a variable or expression twice to get the same information:

> python=3.7 > f "python= {python}" 'python=3.7'

You can add a space around = and use the format specifier as usual:

The format specifier > 10 indicates that the name should be right-aligned within 10 strings. = also applies to more complex expressions:

> > f "{name.upper () [::-1] =}"name.upper () [::-1] = 'CIRE'"

Steering Committee Model (The Python Steering Council)

Technically, the management of Python is not a language function. However, Python 3.8 is the first version of Python that was not developed under Guido van Rossum's benevolent dictatorship. The Python language is now managed by a steering committee of five core developers:

Barry Warsaw

Brett Cannon

Carol Willing

Guido van Rossum

Nick Coghlan

The road to the new governance model of Python is an interesting study of self-organization. Guido van Rosum (Guido van Rossum) founded Python in the early 1990s and is affectionately known as Python's benevolent dictator (BDFL). Over the years, the Python Enhancement recommendation (PEP) has been increasingly involved in decision-making about the Python language. Nevertheless, Guido still has the final say on all new language features.

After a lengthy discussion of assignment expressions, Guido announced his resignation from the BDFL position in July 2018 (for real this time). He deliberately did not appoint a successor. Instead, he asked the core team of developers to figure out how to manage Python in the future.

Fortunately, the PEP process is well established, so it makes sense to use PEP to discuss and decide on a new governance model. In the fall of 2018, PEP proposed several models, including electing a new BDFL (renamed GUIDO) or abandoning centralized leadership to a community model based on consensus and voting. In December 2018, the core developers voted for the steering committee model.

The steering committee consists of five members of the Python community pictured above. After each major Python version is released, a new steering committee will be elected. In other words, there will be an election after the release of Python 3.8.

Although this is an open election, it is expected that most (or even all) of the members of the previous steering committee will be re-elected. The steering committee has the power to make decisions in the broad Python language, but should exercise these powers as little as possible.

You can read all the information about the new governance model in PEP 13, and you can see the process of determining the new model in PEP 8000. For more information, see PyCon 2019 keynote speeches, podcasts on Brett Cannon and Talk Python To Me and Changelog, and follow the steering Committee updates on GitHub.

Other cool new features

There are a lot of other changes in Python 3.8 that are also cool.

Importlib.metadata

A new module is provided in the standard library of Python 3.8: importlib.metadata. Through this module, you can access information about installed packages in your Python installation. Along with its supporting module importlib.resources, importlib.metadata improves the functionality of the old pkg_resources.

For example, you can get some information about pip:

> from importlib import metadata > metadata.version ("pip") '19.2.3' > pip_metadata = metadata.metadata ("pip") > list (pip_metadata) ['Metadata-Version',' Name', 'Version',' Summary', 'Home-page',' Author', 'Author-email',' License', 'Platform',' Classifier', 'Classifier' 'Classifier',' Requires-Python'] > pip_metadata ["Home-page"] 'https://pip.pypa.io/' > pip_metadata ["Requires-Python"]' > = 2.7. ! = 3.4. Len (metadata.files ("pip")) 668

The currently installed version of pip is 19.2.3. Metadata () gives you access to most of the information you see on PyPI. For example, you can see that this version of pip requires Python 2.7 or Python 3.5 or later. Using files (), you can get a list of all the files that make up the pip package. There are about 700 files in this example.

Files () returns a list of Path objects. You can use read_text () to easily view the source code of the package. The following example prints _ _ init__.py from the realpython-reader package:

> [p for p in metadata.files ("realpython-reader") if p.suffix = = ".py"] [PackagePath ('reader/__init__.py'), PackagePath (' reader/__main__.py'), PackagePath ('reader/feed.py') PackagePath ('reader/viewer.py')] > init_path = _ [0] # Underscore access last returned value in the REPL > print (init_path.read_text ()) "Real Python feed reader Import the `feed`module to work with the Real Python feed: > from reader import feed > feed.get_titles () [' Logging in Python', 'The Best Python Books',...] See https://github.com/realpython/reader/ for more information "" # Version of realpython-reader package _ _ version__ = "1.0.0"...

You can also access package dependencies:

> metadata.requires ("realpython-reader") ['feedparser',' html2text', 'importlib-resources',' typing']

Require () lists the dependencies of the package. As you can see, for example, realpython-reader uses feedparser in the background to read and parse article feeds.

There is a reverse port for importlib.metadata on PyPI, which can also be used in earlier versions of Python. You can install using pip:

Try: from importlib import metadata except ImportError: import importlib_metadata as metadata..

New and improved mathematical and statistical functions

Python 3.8 has made many improvements to the existing standard library packages and modules. Mathematics in the standard library has some new features. Math.prod () is similar to the built-in sum (), but for multiplication:

> import math > math.prod ((2,8,7,7)) 784 > 2 * 8 * 7 * 7 784

The two statements are equivalent. Prod () is easier to use when you store factors in iterable objects.

Another new feature is math.isqrt (). You can use isqrt () to find the integer portion of the square root:

The square root of 9 is 3. You can see that isqrt () returns an integer result, while math.sqrt () always returns a floating point number. The square root of 15 is about 3.9. Notice that in this case, isqrt () truncates the answer to the next integer.

Finally, you can now use n-dimensional points and vectors in the standard library more easily. Use math.dist () to find the distance between two points, and math.hypot () to find the length of the vector:

This makes it easier to work with points and vectors using standard libraries. However, if you want to do a lot of calculations on a point or vector, you should check out NumPy.

The statistics module also has several new features:

Statistics.fmean () calculates the average of floating-point numbers.

Statistics.geometric_mean () calculates the geometric average of floating-point numbers.

Statistics.multimode () looks for the most frequent values in the sequence.

Statistics.quantiles () calculates the tangent points used to divide the data into n continuous intervals with equal probability.

The following is an example of using these features:

> > import statistics > data = [9, 3, 2, 1, 1, 2, 7, 9] > statistics.fmean (data) 4.25 > statistics.geometric_mean (data) 3.013668912157617 > statistics.multimode (data) [9,2,1] > > statistics.quantiles (data, nasty 4) [1.25,2.5,8.5]

In Python 3.8, there is a new statistics.NormalDist class, which makes the Gaussian normal distribution more convenient.

To see an example of using NormalDist, you can compare the speed of the new statistics.fmean () to the traditional statistics.mean ():

> > import random > import statistics > > from timeit import timeit > > # Create 10000 random numbers > data = [random.random () for _ in range (10000000)] > # Measure the timeit takes to run mean () and fmean () > t_mean = [timeit ("statistics.mean (data)", number=100, globals=globals ()). For _ in range (30) > t_fmean = [timeit ("statistics.fmean (data)", number=100, globals=globals ()). For _ in range (30) > > # Create NormalDist objects based on the sampled timings > n_mean = statistics.NormalDist.from_samples (t_mean) > n_fmean = statistics.NormalDist.from_samples (t_fmean) > Look at sample mean and standard deviation > n_mean.mean, n_mean.stdev (0.825690647733245,0.07788573997674526) > > n_fmean.mean, n_fmean.stdev (0.010488564966666065,0.0008572332785645231) > > # Calculate the lower 1 percentile of mean > > n_mean.quantiles [0] 0.64450132212

In this example, timeit is used to measure the execution time of mean () and fmean (). To get reliable results, you can have timeit execute each function 100 times and collect 30 such time samples for each function. Based on these examples, you will create two NormalDist objects. Note that if you run the code yourself, it may take a minute to collect different time samples.

NormalDist has many convenient properties and methods, so please refer to the official documentation for a complete list. Check .mean and .stdev, and you will find that the running time of the old statistics.mean () is 0.826 ±0.078 seconds, while the new statistics.fmean () is 0.0105 ±0.0009 seconds. In other words, fmean () is about 80 times faster for this data.

New dangerous syntax warning function

Python has a SyntaxWarning feature that warns you of suspicious syntax that is not SyntaxError. Python 3.8has added some new features to help you during coding and debugging.

The difference between is and = = can be confusing. The latter is used to check whether there is an equal value and is true only if the object is the same. Python 3.8 will warn you when you should use = = instead of is:

> # Python 3.7 > version = "3.7" > > version is "3.7" False > > # Python 3.8 > > version = "3.8" > version is "3.8": 1: SyntaxWarning: "is" with a literal. "Did you mean"? False > version = = "3.8" True

When writing long lists, especially when formatting vertically, it is easy to miss commas. An uncallable tuple error message is issued when you forget the comma in the tuple list. Python 3.8 not only issues warnings, but also points out actual problems:

> [. (1,3)... (2,4).]: 2: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma? Traceback (most recent call last): File "", line 2, in TypeError: 'tuple' object is not callable

This warning correctly identifies the missing comma as the real culprit.

Optimize

Python 3.8.Some optimizations have been made to make the code run faster and some optimizations have reduced memory footprint. For example, it is much faster to find fields in named tuples in Python 3.8 than Python 3.7:

> import collections > from timeit import timeit > Person = collections.namedtuple ("Person", "name twitter") > raymond = Person ("Raymond", "@ raymondh") > # Python 3.7 > timeit ("raymond.twitter", globals=globals ()) 0.05876131607996285 > # Python 3.8 > timeit ("raymond.twitter", globals=globals ()) 0.0377705999400132

As you can see, the speed of finding .Twitter on namedtuple in Python 3.8 has increased by 30-40%. You can save some space when initializing a list from an iterable object with a known length. This saves memory:

> import sys > # Python 3.7 > sys.getsizeof (list (range (20191014) 181719232 > # Python 3.8 > sys.getsizeof (list (range (20191014) 161528168

In this example, the list uses about 11% less memory in Python 3.8 than in Python 3.7.

Other optimizations include higher subprocess performance, faster file replication with shutil, improved default performance in pickle, and faster operator.itemgetter operations. For a complete list of optimizations, see the official documentation.

This is the end of the article on "how to use the new features of Python3.8". Thank you for reading! I believe you all have a certain understanding of the knowledge of "how to use the new features of Python3.8". If you want to learn more, you are welcome to follow the industry information channel.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report