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

it2022-05-05  65

特性 1: 高级解包

使用解包交换变量非常方便,在 python3 中,这个特性得到了加强,现在你可以这样做:

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 获得文件的第一行和最后一行内容。

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)。

如果你不想收集其他参数,你可以用 * 代替 *args,比如这样:

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) ##> 一键删库.

 

所以,以后千万别这样写,为了你的下半生能够过上平静的日子,你应该这样:

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

试一下不合法的调用:

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-d/' % 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')

转载于:https://www.cnblogs.com/rrh4869/p/11175390.html


最新回复(0)