This article lists Python3.6、3.7、3.8、3.9 New features in four versions , Learning them will help to improve the understanding of Python Understanding , Keep up with the latest trends .
New format string method , That is, add... Before the normal string f or F Prefix , The effect is similar to str.format(). such as
name = "red"print(f"He said his name is {name}.") # 'He said his name is red.'
amount to :
print("He said his name is {name}.".format(**locals()))
Besides , This feature also supports nested fields , such as :
import decimalwidth = 10precision = 4value = decimal.Decimal("12.34567")print(f"result: {value:{width}.{precision}}") #'result: 12.35'
You can declare a variable and specify the type as follows :
from typing import List, Dictprimes: List[int] = []captain: str # There is no initial value at this time class Starship: stats: Dict[str, int] = {}
Allow underscores in numbers , To improve the readability of multi digit numbers .
a = 1_000_000_000_000_000 # 1000000000000000b = 0x_FF_FF_FF_FF # 4294967295
besides , String formatting is also supported _ Options , To print out a more readable numeric string :
'{:_}'.format(1000000) # '1_000_000''{:_x}'.format(0xFFFFFFFF) # 'ffff_ffff'
stay Python3.5 in , A new grammar has been introduced async and await To implement collaborative programs . But there is a limit , Cannot use... In the same function body at the same time yield and await.Python3.6 in , This restriction has been lifted , Allows you to define asynchronous generators :
async def ticker(delay, to):"""Yield numbers from 0 to *to* every *delay* seconds.""" for i in range(to): yield i await asyncio.sleep(delay)
Allow in the list list、 aggregate set And the dictionary dict In the parser async or await grammar .
result = [i async for i in aiter() if i % 2]result = [await fun() for fun in funcs if await condition()]
Standard library (The Standard Library) A new module has been added in :secrets. This module is used to generate some random numbers with higher security , Used to manage passwords, account authentication, security tokens, as well as related secrets Data such as .
Python 3.7 On 2018 year 6 month 27 Promulgated by the , Contains many new features and optimizations , Added many new classes , It can be used for data processing 、 Optimization for Script Compilation and garbage collection and faster asynchrony I/O, Mainly as follows :
Use this built-in function , It is equivalent to setting breakpoints through code , Will automatically enter Pbd Debug mode .
If... Is set in the environment variable PYTHONBREAKPOINT=0 This function is ignored . also ,pdb Just one of many available debuggers , You can set up a new PYTHONBREAKPOINT Environment variables to configure the debugger you want to use .
Here is a simple example , The user needs to enter a number , Determine whether it is the same as the target number :
""" Guess the number game """def guess(target): user_guess = input(" Please enter the number you guessed >>> ") if user_guess == target: return " You guessed it !" else: return " Wrong guess. "if __name__ == '__main__': a = 100 print(guess(a))
Unfortunately , Even if the number of guesses is the same as the target number , The result of printing is also ‘ Wrong guess. ’, And there are no exceptions or error messages .
To find out what happened , We can insert a breakpoint , Let's debug . In the past, we usually passed print Dafa or IDE Debugging tools for , But now we can use breakpoint().
""" Guess the number game """def guess(target): user_guess = input(" Please enter the number you guessed >>> ") breakpoint() // Join the line if user_guess == target: return " You guessed it !" else: return " Wrong guess. "if __name__ == '__main__': a = 100 print(guess(a))
stay pdb At the prompt , We can call locals() To view all variables of the current local scope .(pdb There are a lot of orders , You can also run it normally Python sentence )
Please enter the number you guessed >>> 100> c:\moonrong\py3_test\test.py(7)guess()-> if user_guess == target:(Pdb) locals(){'target': 100, 'user_guess': '100'}(Pdb) type(user_guess)<class 'str'>
I see ,target It's an integer , and user_guess Is a string , There is a type comparison error .
from Python 3.5 Start , Type annotations are becoming more and more popular . For those unfamiliar with type cues , This is a completely optional way to annotate code , To specify the type of the variable .
What is annotation ? They are syntax support for associating metadata with variables , It could be any expression , At run time is Python Calculated but ignored . Annotations can be any valid Python expression .
Here is an example of comparison :
# Without type annotation def foo(bar, baz):# With type annotation def foo(bar: 'Describe the bar', baz: print('random')) -> 'return thingy':
The above method , It's actually Python The reinforcement of its own weakly typed language , Hope to obtain certain type reliability and robustness , towards Java And so on .
stay Python 3.5 in , The syntax of annotations is standardized , thereafter ,Python Annotation type hints are widely used in the community .
however , Annotations are just a development tool , have access to PyCharm etc. IDE or Mypy Wait for third-party tools to check , It is not a grammatical restriction .
Our previous guessing program adds type annotations , It should be like this :
""" Guess the number game """def guess(target:str): user_guess:str = input(" Please enter the number you guessed >>> ") breakpoint() if user_guess == target: return " You guessed it !" else: return " Wrong guess. "if __name__ == '__main__': a:int = 100 print(guess(a))
PyCharm Will give us a gray specification error warning , But will not give red syntax error prompt .
When using annotations as type prompts , There are two main problems : Start performance and forward reference .
typing Part of the reason modules are so slow is , The initial design goal was to not modify the core CPython Interpreter implementation typing modular . As type hints become more and more popular , This restriction has been removed , This means that now there is a right typing Core support for .
And for forward references , See the following example :
class User: def __init__(self, name: str, prev_user: User) -> None: pass
The mistake is User The type has not been declared yet , At this time prev_user It can't be defined as User type .
To solve this problem ,Python3.7 Deferred evaluation of comments . also , This change is backwards incompatible , You need to import annotations, Only to Python 4.0 Will become the default behavior .
from __future__ import annotationsclass User: def __init__(self, name: str, prev_user: User) -> None: pass
Or as in the following example :
class C: def validate_b(self, obj: B) -> bool: ...class B: ...
This feature may be Python3.7 More commonly used in the future , What does it do ?
Suppose we need to write the following class :
from datetime import datetimeimport dateutilclass Article(object): def __init__(self, _id, author_id, title, text, tags=None, created=datetime.now(), edited=datetime.now()): self._id = _id self.author_id = author_id self.title = title self.text = text self.tags = list() if tags is None else tags self.created = created self.edited = edited if type(self.created) is str: self.created = dateutil.parser.parse(self.created) if type(self.edited) is str: self.edited = dateutil.parser.parse(self.edited) def __eq__(self, other): if not isinstance(other, self.__class__): return NotImplemented return (self._id, self.author_id) == (other._id, other.author_id) def __lt__(self, other): if not isinstance(other, self.__class__): return NotImplemented return (self._id, self.author_id) < (other._id, other.author_id) def __repr__(self): return '{}(id={}, author_id={}, title={})'.format( self.__class__.__name__, self._id, self.author_id, self.title)
A large number of initialization attributes need to define default values , You may need to rewrite a bunch of magic methods , To print class instances 、 Compare 、 Sorting and de duplication .
If you use dataclasses To transform , It can be written like this :
from dataclasses import dataclass, fieldfrom typing import Listfrom datetime import datetimeimport [email protected](order=True) // Note that there class Article(object): _id: int author_id: int title: str = field(compare=False) text: str = field(repr=False, compare=False) tags: List[str] = field(default=list(), repr=False, compare=False) created: datetime = field(default=datetime.now(), repr=False, compare=False) edited: datetime = field(default=datetime.now(), repr=False, compare=False) def __post_init__(self): if type(self.created) is str: self.created = dateutil.parser.parse(self.created) if type(self.edited) is str: self.edited = dateutil.parser.parse(self.edited)
This makes classes not only easy to set up , And when we create an instance and print it out , It can also automatically generate beautiful strings . When comparing with other class instances , It will also have appropriate behavior . This is because dataclasses In addition to helping us automatically generate _init_ Outside method , Some other special methods have also been generated , Such as repr、eq and hash etc. .
Dataclasses Use fields field To provide default values , Manually construct a field() Function can access other options , This changes the default value . for example , There will be field Medium default_factory Set to a lambda function , This function prompts the user for its name .
from dataclasses import dataclass, fieldclass User: name: str = field(default_factory=lambda: input("enter name"))
stay Python 3.7 in , The generator raises StopIteration After abnormality ,StopIteration The exception will be converted to RuntimeError abnormal , That way, it won't quietly affect the stack framework of the application . This means that some programs that are not very sensitive about how to handle the behavior of the generator will Python 3.7 Throw out RuntimeError. stay Python 3.6 in , This behavior generates a deprecation warning ; stay Python 3.7 in , It will generate a complete error .
An easy way is to use try/except Code segment , stay StopIteration Propagate to the outside of the generator to capture it . A better solution is to rethink how to build the generator ―― for instance , Use return Statement to terminate the generator , Instead of manually triggering StopIteration.
Python The interpreter adds a new command line switch :-X, Allows developers to set many low-level options for the interpreter .
This run-time checking mechanism usually has a significant impact on performance , But it is very useful for developers during debugging .
-X The active options include :
Python 3.7 A new class of time functions in returns nanosecond precision time values . Even though Python It's an interpretative language , however Python Victor, the core developer of • Steiner (Victor Stinner) Claim to report time with nanosecond accuracy . The main reason is , In the process of converting other programs ( Like databases ) Recorded time value , It can avoid losing accuracy .
The new time function uses the suffix ns. for instance ,time.processtime() The nanosecond version of is time.processtimens(). Please note that , Not all time functions have corresponding nanosecond versions .
Python3.8 Version on 2019 year 10 month 14 Promulgated by the , Here are Python 3.8 comparison 3.7 New features .
New syntax :=, Assign a value to a variable in a larger expression . It is affectionately called “ Walrus operators ”(walrus operator), Because it looks like walrus' eyes and ivory .
“ Walrus operators ” At some point you can make your code cleaner , such as :
In the following example , Assignment expressions can avoid calling len () two :
if (n := len(a)) > 10: print(f"List is too long ({n} elements, expected <= 10)")
A similar benefit can be seen in the case that regular expression matching requires the use of matching objects twice , A test is used to determine whether a match has occurred , The other is used to extract sub groups :
discount = 0.0 if (mo := re.search(r'(\d+)% discount', advertisement)): discount = float(mo.group(1)) / 100.0
This operator can also be used in conjunction with while Loop through a value , To detect whether the loop is terminated , And the same value is used again in the loop body :
# Loop over fixed length blocks while (block := f.read(256)) != '': process(block)
Or in a list derivation , Calculate a value in the filter criteria , The same value needs to be used in the expression :
[clean_name.title() for name in names if (clean_name := normalize('NFC', name)) in allowed_names]
Try to limit the use of walrus operators to clear situations , To reduce complexity and improve readability .
Add a function parameter syntax / Used to indicate that some function parameters must be in the form of position only parameters instead of keyword parameters .
This kind of markup syntax is similar to that of help () Use shown Larry Hastings Of Argument Clinic Tool marked C The same function .
In the following example , Shape parameter a and b Is a positional parameter only ,c or d It can be a location parameter or a keyword parameter , and e or f Keyword parameter required :
def f(a, b, /, c, d, *, e, f): print(a, b, c, d, e, f)
Here are the legal calls :
f(10, 20, 30, d=40, e=50, f=60)
however , The following are illegal calls :
f(10, b=20, c=30, d=40, e=50, f=60) # b Cannot be a keyword parameter f(10, 20, 30, 40, 50, f=60) # e Must be a keyword parameter
One use case for this notation is that it allows pure Python Function to completely simulate the existing C The behavior of a function written in code . for example , Built in pow () Function does not accept keyword arguments :
def pow(x, y, z=None, /): "Emulate the built in pow() function" r = x ** y return r if z is None else r%z
Another use case is to exclude keyword parameters when formal parameter names are not required . for example , Built in len () The signature of the function is len (obj, /). This can rule out this clumsy form of invocation :
len(obj='hello') # The "obj" keyword argument impairs readability
Another benefit is that marking a parameter as location only will allow the parameter name to be modified in the future without breaking the customer's code . for example , stay statistics Module , The name of the parameter dist May be modified in the future . This makes the following function description possible :
def quantiles(dist, /, *, n=4, method='exclusive') ...
Because in / The formal parameters on the left are not exposed as available keywords , Other parameter names can still be found in **kwargs Use in :
>>> def f(a, b, /, **kwargs): ... print(a, b, kwargs) ... >>> f(10, 20, a=1, b=2, c=3) # a and b are used in two ways 10 20 {'a': 1, 'b': 2, 'c': 3}
This greatly simplifies the implementation of functions and methods that need to accept arbitrary keyword parameters . for example , Here is collections Code excerpt from module :
class Counter(dict): def __init__(self, iterable=None, /, **kwds): # Note "iterable" is a possible keyword argument
increase = A specifier is used for f-string. In the form of f'{expr=}' Of f The string represents the extension as expression text , Add an equal sign , Plus the evaluation result of the expression . for example :
>>> user = 'eric_idle' >>> member_since = date(1975, 7, 31) >>> f'{user=} {member_since=}' "user='eric_idle' member_since=datetime.date(1975, 7, 31)"
f String format specifiers allow more granular control over the expression results to be displayed :
>>> delta = date.today() - member_since >>> f'{user=!s} {delta.days=:,d}' 'user=eric_idle delta.days=16,075'
= The specifier will output the entire expression , So as to demonstrate the calculation process in detail :
>>> print(f'{theta=} {cos(radians(theta))=:.3f}') theta=30 cos(radians(theta))=0.866
Python Is a dynamically typed language , But it can go through typing Module add type prompt , So that third-party tools can verify Python Code .Python 3.8 to typing Added some new elements , So it can support more robust checking :
multiprocessing Module addition SharedMemory class , Can be in different Python Create shared memory areas between cities .
In the old version of Python in , Data can only be shared between processes by writing to a file 、 Send via network socket , Or adopt Python Of pickle Module serialization, etc . Shared memory provides a faster way to pass data between processes , Thus making Python More efficient multiprocessor and multi-core programming .
Shared memory fragments can be allocated as simple byte areas , It can also be assigned as a list like object that cannot be modified , It can save the number type 、 character string 、 Byte object 、None Objects, etc Python object .
Python Of pickle Modules provide a way to serialize and deserialize Python Methods of data structures or instances , You can save the dictionary as it is for later reading . Different versions Python Supported by pickle Different agreements , and 3.8 Version has a wider range of support 、 More powerful 、 More efficient serialization .
Python 3.8 Introduced 5 edition pickle The protocol can be used in a new way pickle object , It can support Python Buffer protocol , Such as bytes、memoryviews or Numpy array etc. . new pickle Avoid a lot in pickle These objects are used for memory copy operations .
NumPy、Apache Arrow Wait for external libraries in their respective Python The binding supports new pickle agreement . new pickle It can also be used as Python 3.6 and 3.7 The plug-in uses , It can be downloaded from PyPI Installation on .
Dictionary adds two new operators :「|」 and 「|=」.「|」 Operator is used to merge dictionaries ,「|=」 The operator is used to update the dictionary .
Dictionary merge :
>>> a = {‘farhad’: 1, 'blog’: 2,'python’: 3} >>> b = {’farhad’: 'malik’,'topic’: 'python3.9’}>>> a | b {’blog’: 2, 'python’: 3, ’farhad’:’malik’,'topic’: 'python3.9’} >>> b | a {’farhad’: 1,’blog’: 2, 'python’: 3,'topic’:’python3.9’ }
Dictionary update :
>>> a |= b >>> a {’blog’: 2, 'python’: 3,’farhad’:’malik’}
Python 3.9 It is proposed to use high-performance and stable PEG Instead of the current parser based on LL(1) Of Python Parser .
Current CPython The parser is based on LL(1),LL(1) The parser is a top-down parser , It parses the input from left to right .
Python 3.9 The proposal will LL(1) Replace with new based on PEG The parser , This means that it will release the current LL(1) Grammar is right Python The limitation of . Besides , The current parser fixes many of the hack. therefore , In the long run , This reduces maintenance costs .
Python 3.9 Add two new functions to str object :
The first function removes the prefix :str.removeprefix(prefix)
The second function removes the suffix :str.removesuffix(suffix)
'farhad_python'.removeprefix('farhad') #returns python 'farhad_python'.removesuffix('python') #returns farhad
Python 3.9 By deleting the parallel type hierarchy , Make annotating programs easier .Python 3.9 Support typing Generic syntax in all standard collections of modules .
We can list or dict Directly as type annotations for lists and dictionaries , Instead of relying on typing.List perhaps typing.Dict. therefore , The code now looks simpler , And easier to understand and explain .
def print_value(input: str): print(input) # We would get notified if the input is not a string
zoneinfo Modules are created to support IANA Time Zone Database . Yes IANA Time zone database support has been added to the standard library .
IANA The time zone is often called tz or zone info. There are many with different search paths IANA The time zone , Used to date-time Object designation IANA The time zone . for example , We can put the right datetime Object to set the search path 「Continent/City」 To set up tzinfo.
dt = datetime(2000, 01, 25, 01, tzinfo=ZoneInfo("Europe/London"))
If you pass in an invalid key , Will trigger zoneinfo.ZoneInfoNotFoundError abnormal .
concurrent.futures.Executor.shutdown() A new parameter has been added to cancel_futures. This parameter cancels concurrent tasks that have not been executed . stay Python 3.9 Previously, the main process could only be shut down after all concurrent tasks were completed executor object .
New parameters cancel_futures Has been added to ThreadPoolExecutor as well as ProcessPoolExecutor. The way it works is : When the value of the parameter is True when , Calling shutdown() Function to cancel all pending tasks .
Python 3.9 For asynchronous programming (asyncio) And multi process library .
1) Because of security considerations ,asyncio.loop.createdatagramendpoint() Parameters are no longer supported reuse_address.
2) Added coroutines、shutdowndefaultexecutor() and asyncio.tothread() .shutdowndefaultexecutor Responsible for turning off the default executor,asyncio.tothread() Mainly used to run in a single thread IO Intensive function , To avoid a cycle of events .
On the improvement of multi process library ,Python 3.9 towards multiprocessing.SimpleQueue Class adds new methods close().
This method can explicitly close the queue . This will ensure that the queue is closed and does not stay longer than expected . It is worth noting that , Once the queue is closed , Can't call get()、put() and empty() Method .
Python3.9 Previous versions are imported Python The main problem with the library is : When the relative Import exceeds its top-level package ,Python Inconsistent import behavior in .
builtins.import() trigger ValueError, and importlib.import() trigger ImportError.Python3.9 Version is fixed , It will lead to ImportError.
Python 3.9 New functions have been added in version random.Random.randbytes(). This function can be used to generate random bytes .
Python Support the generation of random numbers , But what if you need to generate random bytes ? stay Python3.9 Before the release , Developers must find ways to generate random bytes . Although they can use os.getrandom()、os.urandom() perhaps secrets.token_bytes() To generate random bytes , But these methods cannot generate pseudo-random patterns .
To ensure that random numbers are generated in accordance with the expected behavior , And the process can be repeated , Developers often put seeds (seed) And random.Random Use modules together . therefore ,Python 3.9 Added random.Random.randbytes() Method , Generate random bytes in a controlled manner .
stay Python 3.9 Before the release , For all nonzero n,"".replace("",s,n) Returns an empty string instead of a s. This error confuses the user , And lead to inconsistent application behavior .
Python 3.9 Fixed the problem , No matter n Is it 0, The results are consistent with "".replace("", s) Agreement .
"".replace("", "blog", 1) Returns ’'One would expect to see blog"".replace("","|", 1) Returns ’'One would expect to see |"".replace("","prefix") Howver returns ’prefix'
If you want to know more details , Please refer to the official documents .