其他语言无法比拟的Python特性

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:
打开文件。
然而,大多数开发人员不知道其内部是如何运作的,也不知道如何自己创建。
实际上,一个上下文管理器只是一个实现方法enterexit的类。
下面是一个求质数的一个上下文管理器的例子:

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值