Python有着丰富精巧的功能和技巧,会让你惊叹“哇!Python这么酷”。
下面看看python特有的一些brilliant的特性:
1、生成器
生成器是产生一个值的序列的对象,它可以用作迭代器,也就是可以用于for语句,或者用于next函数中来得到下一个值。
含有yield关键字的函数就是生成器,如:
def fibonacci_generator():
a, b = 0, 1
while True:
yield a
a, b = b, a + b
# Print all the numbers of the Fibonacci sequence that are lower than 1000
for i in fibonacci_generator():
if i > 1000:
break
print(i)
对于简单的情况,可以使用生成器表达式创建生成器。与列表相反,值将在运行中计算,而不是一次性全部计算并存储在内存中。
构建一个生成器表达式a,就可以迭代地使用a:
a = (x * x for x in range(100))
# a is a generator object
print(type(a))
#<class 'generator'>
# Sum all the numbers of the generator
print(sum(a))
#328350
# There are no elements left in the generator
print(sum(a))
#0
2、collections模块
collections是标准库中实现替代容器数据类型的一个模块。
例如,一个Counter是一个集合,其中元素被存储为字典的键,而它们的计数被存储为字典的值:
from collections import Counter
a = Counter('blue')
b = Counter('yellow')
print(a) #Counter({'e': 1, 'l': 1, 'b': 1, 'u': 1})
print(b) #Counter({'l': 2, 'e': 1, 'y': 1, 'w': 1, 'o': 1})
print((a + b).most_common(3)) #[('l', 3), ('e', 2), ('y', 1)]
defaultdict是dict的一个子类,它允许调用时传入一个工厂函数,这个函数在键值缺失时自动生成新的值。
from collections import defaultdict
my_dict = defaultdict(lambda: 'Default Value')
my_dict['a'] = 42
print(my_dict['a'])
print(my_dict['b'])
上面,凡是没有值的键,都会有默认的一个值‘Default Value’
defaultdict还可用于创建一个树型数据结构。
from collections import defaultdict
import json
def tree():
"""
Factory that creates a defaultdict that also uses this factory
"""
return defaultdict(tree)
root = tree()
root['Page']['Python']['defaultdict']['Title'] = 'Using defaultdict'
root['Page']['Python']['defaultdict']['Subtitle'] = 'Create a tree'
root['Page']['Java'] = None
print(json.dumps(root, indent=4))
输出形如:
{
"Page": {
"Java": null,
"Python": {
"defaultdict": {
"Subtitle": "Create a tree",
"Title": "Using defaultdict"
}
}
}
}
3、itertools模块
itertools是标准库中的一个模块,可用于创建迭代器以实现有效的循环。
例如,permutations会生成一组序列的所有可能排列(全排列):
from itertools import permutations
for p in permutations([1,2,3]):
print(p)
输出全排列:
(1, 2, 3)
(1, 3, 2)
(2, 1, 3)
(2, 3, 1)
(3, 1, 2)
(3, 2, 1)
combinations会根据所选择的项目个数n,生成一组序列中的所有可能的n项的组合方式,使得(不同于permutations)顺序无关紧要:
from itertools import combinations
for c in combinations([1, 2, 3, 4], 2):
print(c)
输出:
(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
itertools还包含其他实用函数,例如chain,它采用迭代方式,创建一个新的迭代器,由给定的迭代顺序返回元素形成单个序列,如下面,把多个序列合成一个:
from itertools import chain
for c in chain(range(3), range(12, 15)):
print(c)
输出:
0
1
2
12
13
14
4、packing/unpacking
*运算符,被称为拆包运算符,允许非常方便地从列表或元组到独立变量或参数的转变,反之亦可。
拆包:
a, *b, c = [2, 7, 5, 6, 3, 4, 1]
print(a)
print(b)
print(c)
输出:
2
[7, 5, 6, 3, 4]
1
反过来也是可以的,你可以定义一个函数,将单个tuple里的所有参数和单个dict里的所有的关键字参数组包。
组包:
def repeat(count, name):
for i in range(count):
print(name)
print("Call function repeat using a list of arguments:")
args = [4, "cats"]
repeat(*args)
print("Call function repeat using a dictionary of keyword arguments:")
args2 = {'count': 4, 'name': 'cats'}
repeat(**args2)
输出如下:
Call function repeat using a list of arguments:
cats
cats
cats
cats
Call function repeat using a dictionary of keyword arguments:
cats
cats
cats
cats
打包函数参数(python的函数可以接受任意数量的参数):
def f(*args, **kwargs):
print("Arguments: ", args)
print("Keyword arguments: ", kwargs)
f(3, 4, 9, foo=42, bar=7)
输出:
Arguments: (3, 4, 9)
Keyword arguments: {'foo': 42, 'bar': 7}
5、装饰器
装饰器是一个接受函数作为参数,并且返回函数的函数。
例如,在下面的代码中,cache函数用作装饰器来记住已经计算出的斐波那契数:
def cache(function):
cached_values = {} # Contains already computed values
def wrapping_function(*args):
if args not in cached_values:
# Call the function only if we haven't already done it for those parameters
cached_values[args] = function(*args)
return cached_values[args]
return wrapping_function
@cache
def fibonacci(n):
print('calling fibonacci(%d)' % n)
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print([fibonacci(n) for n in range(1, 9)])
输出如下:
calling fibonacci(1)
calling fibonacci(2)
calling fibonacci(0)
calling fibonacci(3)
calling fibonacci(4)
calling fibonacci(5)
calling fibonacci(6)
calling fibonacci(7)
calling fibonacci(8)
[1, 1, 2, 3, 5, 8, 13, 21]
如果是:
def cache(function):
cached_values = {} # Contains already computed values
def wrapping_function(*args):
if args not in cached_values:
# Call the function only if we haven't already done it for those parameters
cached_values[args] = function(*args)
return cached_values[args]
return wrapping_function
@cache
def fibonacci(n):
print('calling fibonacci(%d)' % n)
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print(fibonacci(9))
那么就会输出:
calling fibonacci(9)
calling fibonacci(8)
calling fibonacci(7)
calling fibonacci(6)
calling fibonacci(5)
calling fibonacci(4)
calling fibonacci(3)
calling fibonacci(2)
calling fibonacci(1)
calling fibonacci(0)
34
python的functools模块提供了几个装饰器,例如lru_cache,它可以实现我们刚刚做的:存储。当使用相同的参数调用给定的函数时,它可以保存最近的调用来节省时间:
from functools import lru_cache
@lru_cache(maxsize=None)
def fibonacci(n):
print('calling fibonacci(%d)' % n)
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)
print([fibonacci(n) for n in range(1, 9)])
输出同上面:
calling fibonacci(1)
calling fibonacci(2)
calling fibonacci(0)
calling fibonacci(3)
calling fibonacci(4)
calling fibonacci(5)
calling fibonacci(6)
calling fibonacci(7)
calling fibonacci(8)
[1, 1, 2, 3, 5, 8, 13, 21]
6、上下文管理器
上下文管理器主要用于正确管理资源。上下文管理器最常用的用途是通过语句
with open(“workfile”, “r”) as f:
打开文件。
然而,大多数开发人员不知道其内部是如何运作的,也不知道如何自己创建。
实际上,一个上下文管理器只是一个实现方法enter和exit的类。
下面是一个求质数的一个上下文管理器的例子:
from time import time
class Timer():
def __init__(self, message):
self.message = message
def __enter__(self):
self.start = time()
print("start!")
return None # could return anything, to be used like this: with Timer("Message") as value:
def __exit__(self, type, value, traceback):
elapsed_time = (time() - self.start) * 1000
print(self.message.format(elapsed_time))
with Timer("Elapsed time to compute some prime numbers: {}ms"):
primes = []
for x in range(2, 500):
if not any(x % p == 0 for p in primes):
primes.append(x)
print("Primes: {}".format(primes))
输出如下:
start!
Primes: [2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499]
Elapsed time to compute some prime numbers: 68.00413131713867ms
想简单使用上下文管理器,也可以使用带有yield关键字的生成器函数,也可使用@contextmanager装饰器,使我们自己的函数变为上下文管理器:
from contextlib import contextmanager
@contextmanager
def colored_output(color):
print("\033[%sm" % color, end="\n")
yield
print("\033[0m", end="\n")
print("Hello, World!")
with colored_output(31):
print("Now in color!")
print("So cool.")
输出:
Hello, World!
[31m
Now in color!
[0m
So cool.
翻译自:
https://tech.io/playgrounds/500/advanced-python-features/content/advanced-python-features