使用解包交换变量非常方便,在 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) 的方式调用这个方法,以后我们要修改这个接口的传参方式时,也不用修改已有代码啦。
现在你在写一个函数,由于可能会出现错误,你打算 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
刚刚给你的代码其实不正确,OSError 实际上包含了很多类异常,比如权限不够,文件没找到,不是一个目录等,而我们默认是权限不够。
python3 添加了大量的新 Exception 类型,所以你可以这样做:
def mycopy(source, dest): try: shutil.copy2(source, dest) except PermissionError: raise NotImplementedError("automatic sudo injection")
在 python3 中,range,zip,dict.values 以及其它,都是返回迭代器,所以这对内存很友好。
如果你希望得到一个列表,要做的仅仅是在外层加一个 list,显示的声明永远比隐式地更好,你很难再写出一个吃内存的代码了。
在 python3 中,这个非常 buggy 的特性被取消啦:
'one' > 2 --------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-33-55b5025c2335> in <module>() ----> 1 'one' > 2 TypeError: unorderable types: str() > int()
如果你用 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()
现在你可以用更方便的协程调用了
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'))
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
听说你会中文编程?
简历 = "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'>}
这是新手遇到的最多的问题,为什么我的命令行输出是乱码?
python2 中的 str 是字节数组
python3 中的 str 是 unicode 字符串,只有 unicode 才能表示中文。
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)
这是一个特别好用的面向对象路径处理库,更好的写法
from pathlib import Path directory = Path("/etc") filepath = directory / "hosts" if filepath.exists(): print('hosts exist')转载于:https://www.cnblogs.com/rrh4869/p/11175390.html
