Python2即将淘汰,分享python3 才能用的特性(13个)

特性 1: 高级解包

使用解包交换变量很是方便,在 python3 中,这个特性获得了增强,如今你能够这样作:python

a, b, *rest = range(10) print('a:', a) print('b:', b) print('rest:', rest) ##> a: 0 ##> b: 1 ##> rest: [2, 3, 4, 5, 6, 7, 8, 9] 

rest 能够在任何位置,好比这样:编程

a, *rest, b = range(10) print('rest', rest) ##> rest [1, 2, 3, 4, 5, 6, 7, 8] *rest, b = range(10) print('rest', rest) ##> rest [0, 1, 2, 3, 4, 5, 6, 7, 8] 

使用 python 得到文件的第一行和最后一行内容。api

with open('use_python_to_profit.txt') as f: first, *_, last = f.readlines() # 注意,这会读取全部内容到内存中 print('first:', first) print('last:', last) ##> first: step 1: use python ##> last: step 10: profit 

 

特性 2: 强制关键词参数数组

def f(a, b, *args, option=True): pass 

若是你用以上写法来写一个函数,那么你限定了调用参数时,必需要这样写 f(a, b, option=True)app

若是你不想收集其余参数,你能够用 * 代替 *args,好比这样:async

def f(a, b, *, option=True): pass 

当你碰上这种事情:哎呀,我不当心传递太多参数给函数,其中之一会被关键字参数接收,而后程序原地爆炸了。函数

def sum(a, b, biteme=False): if biteme: print('一键删库') else: return a + b sum(1, 2) ##> 3 sum(1, 2, 3) ##> 一键删库. 

 

因此,之后千万别这样写,为了你的下半生可以过上平静的日子,你应该这样:fetch

def sum(a, b, *, biteme=False): if biteme: print('一键删库') else: return a + b 

试一下不合法的调用:this

sum(1, 2, 3) ##> TypeError: sum() takes 2 positional arguments but 3 were given 

有时你会想写这样一个方法编码

def maxall(iterable, key=None): """ 返回一个列表中的最大值 """ key = key or (lambda x: x) m = max(iterable, key=key) return [i for i in iterable if key(i) == key(m)] maxall(['a', 'ab', 'bc'], len) ##> ['ab', 'bc'] 

咱们应该用max(iterable, *, key=None)来写这个函数。你在写代码时,也能够用关键词参数使你的 api 具备更好的扩展性。

def extendto(value, *, shorter=None, longer=None): """ Extend list `shorter` to the length of list `longer` with `value` """ if shorter is None or longer is None: raise TypeError('`shorter` and `longer` must be specified') if len(shorter) > len(longer): raise ValueError('The `shorter` list is longer than the `longer` list') shorter.extend([value]*(len(longer) - len(shorter))) 

咱们能够用 extendto(10, shorter=a, longer=b) 的方式调用这个方法,之后咱们要修改这个接口的传参方式时,也不用修改已有代码啦。

 

特性 3:链式异常

如今你在写一个函数,因为可能会出现错误,你打算 catch 可能出现的异常,作一些额外的工做,而后再抛出另外一种异常。

import shutil def mycopy(source, dest): try: shutil.copy2(source, dest) except OSError: # We don't have permissions. More on this later raise NotImplementedError("automatic sudo injection") 

python3 中会依次把异常记录下来

mycopy(1, 2)

---------------------------------------------------------------------------
SameFileError                             Traceback (most recent call last)
<ipython-input-26-7970d14296a0> in mycopy(source, dest)
      4     try:
----> 5         shutil.copy2(source, dest)
      6     except OSError: # We don't have permissions. More on this later

/usr/lib/python3.5/shutil.py in copy2(src, dst, follow_symlinks)
    250         dst = os.path.join(dst, os.path.basename(src))
--> 251     copyfile(src, dst, follow_symlinks=follow_symlinks)
    252     copystat(src, dst, follow_symlinks=follow_symlinks)

/usr/lib/python3.5/shutil.py in copyfile(src, dst, follow_symlinks)
     97     if _samefile(src, dst):
---> 98         raise SameFileError("{!r} and {!r} are the same file".format(src, dst))
     99 

SameFileError: 1 and 2 are the same file

During handling of the above exception, another exception occurred:

NotImplementedError                       Traceback (most recent call last)
<ipython-input-27-ddb6bcd98254> in <module>()
      1 # python3 中会依次把异常记录下来
----> 2 mycopy(1, 2)

<ipython-input-26-7970d14296a0> in mycopy(source, dest)
      5         shutil.copy2(source, dest)
      6     except OSError: # We don't have permissions. More on this later
----> 7         raise NotImplementedError("automatic sudo injection")

NotImplementedError: automatic sudo injection

 

特性 4: 更好用的 OSError 子类

刚刚给你的代码其实不正确,OSError 实际上包含了不少类异常,好比权限不够,文件没找到,不是一个目录等,而咱们默认是权限不够。

python3 添加了大量的新 Exception 类型,因此你能够这样作:

def mycopy(source, dest): try: shutil.copy2(source, dest) except PermissionError: raise NotImplementedError("automatic sudo injection") 

 

特性 5: 一切皆迭代器

def naivesum(N): A = 0 for i in range(N + 1): A += i return A naivesum(100000000) # 内存爆炸 

 

在 python3 中,range,zip,dict.values 以及其它,都是返回迭代器,因此这对内存很友好。

若是你但愿获得一个列表,要作的仅仅是在外层加一个 list,显示的声明永远比隐式地更好,你很难再写出一个吃内存的代码了。

 

特性 6: 不是一切都能比较

 

在 python3 中,这个很是 buggy 的特性被取消啦:

'one' > 2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-33-55b5025c2335> in <module>()
----> 1 'one' > 2

TypeError: unorderable types: str() > int()

 

特性 7: yield from

若是你用 generator 的话,这个是一个很是好的特性。在之前,你是这么写代码的:

for i in gen(): yield i 

如今是这样

yield from gen() 

没有看懂?来一个例子,好比这样,咱们但愿获得 [0, 0, 1, 1, 2, 2, ...] 的列表用于迭代,咱们有如下写法:

# 不错的方法,使用 yield def dup(n): for i in range(n): yield i yield i # 更好的方法,使用 yield from def dup(n): for i in range(n): yield from [i, i] 

咱们知道,迭代器的方式很是好,首先在内存上它颇有优点,而且能够按需计算,每次只计算要用的值。若是你须要一个列表的时候,只须要在外层加一个 list,若是你须要切片 slicing,能够用 itertools.islice()

 

特性 8: asyncio

如今你能够用更方便的协程调用了

async def fetch(host, port): r, w = await open_connection(host, port) w,write(b'GET /HTTP/1.0\r\n\r\n') while (await r.readline()).decode('latin-1').strip(): pass body = await r.read() return body async def start(): data = await fetch('Welcome to Python.org', 80) print(data.deode('utf-8')) 

 

特性 9: 新的标准库

ipaddress 库

import ipaddress print(ipaddress.ip_address('192.168.0.1')) print(ipaddress.ip_address('2001:db8::')) ##> 192.168.0.1 ##> 2001:db8:: 

functools.lrc_cache 装饰器

from functools import lru_cache from urllib.error import HTTPError import urllib.request @lru_cache(maxsize=32) def get_pep(num): 'Retrieve text of a Python Enhancement Proposal' resource = 'http://www.python.org/dev/peps/pep-%04d/' % num try: with urllib.request.urlopen(resource) as s: return s.read() except HTTPError: return 'Not Found' for n in 8, 290, 308, 320, 8, 218, 320, 279, 289, 320, 9991: pep = get_pep(n) print(n, len(pep)) get_pep.cache_info() ##> CacheInfo(hits=3, misses=8, maxsize=32, currsize=8) 

enum 类

from enum import Enum class Color(Enum): red = 1 green = 2 blue = 3 

 

特性 10: Fun

据说你会中文编程?

简历 = "knows python" π = 3.1415926 

类型标注

def f(a: int, b: int = 2) -> int: return 10 print(f.__annotations__) ##> {'return': <class 'int'>, 'a': <class 'int'>, 'b': <class 'int'>} 

 

特性 11: Unicode 编码

这是新手遇到的最多的问题,为何个人命令行输出是乱码?

python2 中的 str 是字节数组

python3 中的 str 是 unicode 字符串,只有 unicode 才能表示中文。

 

特性 12: 矩阵相乘

python3 中 @ 能够被重载了,因此用 numpy 中的矩阵乘法时能够这么来(我在 tensorflow 中也常常这样写)

import numpy as np a = np.array([[1, 0], [0, 1]]) b = np.array([[4, 1], [2, 2]]) # 旧写法 print(np.dot(a, b)) # 新写法 print(a @ b) 

 

特性 13: pathlib

这是一个特别好用的面向对象路径处理库,更好的写法

from pathlib import Path directory = Path("/etc") filepath = directory / "hosts" if filepath.exists(): print('hosts exist')