print(message)
greet('hello world')
# 输出
wrapper of decorator
hello world
带自定义参数的装饰器
def repeat(num):
def my_decorator(func):
def wrapper(*args, **kwargs):
for i in range(num):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
return my_decorator
@repeat(4)
def greet(message):
print(message)
greet('hello world')
# 输出:
wrapper of decorator
hello world
wrapper of decorator
hello world
wrapper of decorator
hello world
wrapper of decorator
hello world
上述 green() 函数被装饰以后,它的元信息会发生改变,可勇敢 greet__name__
来查看。可通过内置装饰器来解决这个问题
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
print('wrapper of decorator')
func(*args, **kwargs)
return wrapper
@my_decorator
def greet(message):
print(message)
greet.__name__
# 输出
'greet'
类装饰器
class Count:
def __init__(self, func):
self.func = func
self.num_calls = 0
def __call__(self, *args, **kwargs):
self.num_calls += 1
print('num of calls is: {}'.format(self.num_calls))
return self.func(*args, **kwargs)
@Count
def example():
print("hello world")
example()
# 输出
num of calls is: 1
hello world
example()
# 输出
num of calls is: 2
hello world
装饰器支持嵌套使用
@decorator1
@decorator2
@decorator3
def func():
...
# 等价于
decorator1(decorator2(decorator3(func)))
装饰器使用场景:
- 身份认证
- 日志记录
- 输入合理性检查
- 缓存(LRU cache)
metaclass 是 Python 黑魔法级别的语言特性,它可以改变正常 Python 类型的创建过程。
- 所有 Python 的用户定义类,都是 type 这个类的实例
- 用户自定义类,只不过是 type 类的 __ call __ 运算符重载
- metaclass 是 type 的子类,通过替换 type 的 __ call __ 运算符重载机制,超越变形正常的类
class Mymeta(type):
def __init__(self, name, bases, dic):
super().__init__(name, bases, dic)
print('===>Mymeta.__init__')
print(self.__name__)
print(dic)
print(self.yaml_tag)
def __new__(cls, *args, **kwargs):
print('===>Mymeta.__new__')
print(cls.__name__)
return type.__new__(cls, *args, **kwargs)
def __call__(cls, *args, **kwargs):
print('===>Mymeta.__call__')
obj = cls.__new__(cls)
cls.__init__(cls, *args, **kwargs)
return obj
class Foo(metaclass=Mymeta):
yaml_tag = '!Foo'
def __init__(self, name):
print('Foo.__init__')
self.name = name
def __new__(cls, *args, **kwargs):
print('Foo.__new__')
return object.__new__(cls)
foo = Foo('foo')
迭代器和生成器
- 容器时可迭代对象,可迭代对象调用 iter() 函数,可以得到一个迭代器。迭代器可以通过 next() 函数来得到下一个元素,从而支持遍历
- 生成器时一种特殊的迭代器,合理使用生成器,可以降低内存占用、优化程序结构、提高程序速度
- 生成器在 Python 2 的版本上,是协程的一种重要实现方式;而 Python 3.5 引入的 async、await 语法糖,生成器实现协程的方式就已经落后了。
协程
协程是实现并发编程的一种方式
- 协程和多线程的区别,主要在于两点,一是协程为单线程;二是协程由用户决定,在哪些地方交出控制权,切换到下一个任务
- 协程的写法更加简洁清晰;把 async/await 语法和 create_task 结合起来用,对于中小级别的并发需求已经毫无压力
生产者/消费者 模型
import asyncio
import random
async def consumer(queue, id):
while True:
val = await queue.get()
print('{} get a val: {}'.format(id, val))
await asyncio.sleep(1)
async def producer(queue, id):
for i in range(5):
val = random.randint(1, 10)
await queue.put(val)
print('{} put a val: {}'.format(id, val))
await asyncio.sleep(1)
async def main():
queue = asyncio.Queue()
consumer_1 = asyncio.create_task(consumer(queue, 'consumer_1'))
consumer_2 = asyncio.create_task(consumer(queue, 'consumer_2'))
producer_1 = asyncio.create_task(producer(queue, 'producer_1'))
producer_2 = asyncio.create_task(producer(queue, 'producer_2'))
await asyncio.sleep(10)
consumer_1.can