Python高级语法
内置类型
- list:动态的,大小可改变
- tuple:不可变,一旦创建不能修改
- dict:键值映射
- set :可变的、无序的、有限的集合,元素唯一
高级语法
迭代器
迭代器是一个实现了迭代器协议的容器对象,主要基于以下两个方法
__next__
: 返回容器的下一个元素__iter__
: 返回迭代器本身
class CountDown:
def __init__(self, step):
self.step = step
def __next__(self):
if self.step <= 0:
raise StopIteration
self.step -= 1
return self.step
def __iter__(self):
return self
for element in CountDown(4):
print(element)
生成器(yield语句)
- 生成器可以暂停函数并放回一个中间结果,该函数会保存执行上下文,稍后在必要时可以恢复
def power(values):
for value in values:
print("powering %s" % value)
yield value
def adder(values):
for value in values:
print("adding to %s" % value)
if value % 2 == 0:
yield value + 3
else:
yield value + 2
elements = [1, 4, 7, 9, 12, 19]
results = adder(power(elements))
next(results)
- 生成器另一个重要特性,就是能够利用
next
函数与调用的代码进行交互,yield
变成一个表达式,而值可以通过send
的新方法来传递
def psychologist():
print("Please tell me you problems")
while True:
answer = (yield)
if answer is not None:
if answer.endswith("?"):
print("Do not ask yourseld too much questions")
if 'goo' in answer:
print("That's good")
if 'bad' in answer:
print("Do not be so nagative")
free = psychologist()
next(free)
free.send("hello?")
free.send("good")
free.send("bad")
装饰器
作用是使函数包装与方法包装(一个函数,接受函数并返回其增强函数)变得更容易阅读和理解
作为一个函数
编写自定义装饰器最简单的方法就是编写一个函数
def myDecorator(function):
def wrapped(*args, **kwargs):
print("decorator....")
result = function(*args, **kwargs)
return result
return wrapped
@myDecorator
def test():
print("decorator test")
作为一个类
非参数化装饰器用作类的通用模式:
class DecoratorAsClass:
def __init__(self, function):
self.function = function
def __call__(self, *args, **kwargs):
result = function(*args, **kwargs)
return result
参数化装饰器
使用参数化的装饰器,需要用到第二层包装
def repeat(number=3):
def actual_decorator(function):
def wrapper(*args, **kwargs):
for _ in range(number):
result = function(*args, **kwargs)
return result
return wrapper
return actual_decorator
@repeat(2)
def foo():
print("foo")
保存内省的装饰器
- 使用装饰器的常见错误是在使用装饰器时不保存函数元数据(主要是文档字符串和原始函数名),装饰器组合创建了一个新函数,并放回了一个新对象,但却完全没有考虑原始函数的标识,这将会使得调试这样装饰过的函数更加困难,也会破坏可能用到的大多数自动生成文档的工具,因为无法访问原始的文档字符串和函数签名。
def dummyDecorator(function):
def wrapped(*args, **kwargs):
"""包装函数内部文档"""
result = function(*args, **kwargs)
return result
return wrapped
@dummyDecorator
def functionWithImportantDocstring():
"""这是我们想要保存重要文档字符串"""
以上的问题丢失了原始名称和文档字符串
In [48]: functionWithImportantDocstring.__name__
Out[48]: 'wrapped'
In [49]: functionWithImportantDocstring.__doc__
Out[49]: '包装函数内部文档'
解决这个问题的正确方法,就是使用functools
模块内置的wraps
装饰器
from functools import wraps
def preservingDecorator(function):
@wraps(function)
def wrapped(*args, **kwargs):
"""包装函数内部文档"""
result = function(*args, **kwargs)
return result
return wrapped
@preservingDecorator
def functionWithImportantDocstring():
"""这是我们想要保存重要文档字符串"""
In [51]: functionWithImportantDocstring.__name__
Out[51]: 'functionWithImportantDocstring'
In [52]: functionWithImportantDocstring.__doc__
Out[52]: '这是我们想要保存重要文档字符串'
常见的装饰器模式
- 参数检查
- 缓存
- 代理
- 上下文提供者
参数检查
检查函数接受或返回的参数,在特定的上下文中执行时可能有用。
例子:如果一个函数要通过XML-RPC来调用,那么Python无法像静态语言那样直接提供其完整签名,当XML-RPC客户端请求签名时,就需要这个功能来提供内省能力。
自定义装饰器可以提供这种类型的签名,并确保输入和输出代表自定义的签名参数。
rpc_info = {}
def xmlrpc(in_=(), out=(type(None),)):
def _xmlrpc(function):
# 注册签名
func_name = function.__name__
rpc_info[func_name] = (in_, out)
def _checkTypes(elements, types):
"""用来检查类型的子函数"""
if len(elements) != len(types):
raise TypeError('argment count is wrong')
typed = enumerate(zip(elements, types))
for index, couple in typed:
arg, of_the_right_type = couple
if isinstance(arg, of_the_right_type):
continue
raise TypeError(
'arg #%d should be %s' % (index, of_the_right_type))
def _xmlrpc(*args): # 没有允许的关键词
# 检查输入的内容
checkableArgs = args[1:]
_checkTypes(checkableArgs, in_)
# 运行函数
res = function(*args)
# 检查输出的内容
if not type(res) in (tuple, list):
checkableRes = (res,)
else:
checkableRes = res
_checkTypes(checkableRes, out)
# 函数及其类型检查成功
return res
return _xmlrpc
return _xmlrpc
装饰器将函数注册到全局字典中,并将其参数和返回值保存在一个类型列表中。下面是使用示例
class RPCView:
@xmlrpc((int, int))
def meth1(self, int1, int2):
print("received %d and %d" % (int1, int2))
@xmlrpc((str, ), (int,))
def meth2(self, phrase):
print('received %s' % phrase)
return 12
测试:
In [15]: rpc_info
Out[15]: {'meth1': ((int, int), (NoneType,)), 'meth2': ((str,), (int,))}
In [16]: my = RPCView()
In [17]: my.meth1(1, 2)
received 1 and 2
In [18]: my.meth2(2)
TypeError: arg #0 should be <class 'str'>
In [23]: my.meth2('2')
received 2
Out[23]: 12
缓存
缓存装饰器可以将输出与计算它所需要的参数放在一起,并在后续的调用中直接返回它。这种行为被称为memoizing
import time
import hashlib
import pickle
cache = {}
def isObsolete(entry, duration):
return time.time() - entry['time'] > duration
def computeKey(function, args, kw):
key = pickle.dumps((function.__name__, args, kw))
return hashlib.sha1(key).hexdigest()
def memoize(duration=10):
def _memoize(function):
def _memoize(*args, **kw):
key = computeKey(function, args, kw)
# 是否拥有
if (key in cache and not isObsolete(cache[key], duration)):
print("we got a winner")
return cache[key]['value']
# 计算
result = function(*args, **kw)
# 保存结果
cache[key] = {
'value': result,
'time': time.time()
}
return result
return _memoize
return _memoize
测试:
@memoize()
def veryComplexStuff(a, b):
return a + b
In [28]: veryComplexStuff(2, 2)
Out[28]: 4
In [29]: veryComplexStuff(2, 2)
we got a winner
Out[29]: 4
@memoize(1) # 1秒后令缓存失效
def veryComplexStuff(a, b):
return a + b
代理
代理装饰器使用全局机制来标记和注册函数
例子:根据当前用户来保护代理访问的安全层可以使用集中式检查器和相关的可调用对象要求的权限来实现。
class User(object):
def __init__(self, roles):
self.roles = roles
class Unauthorized(Exception):
pass
def protect(role):
def _protect(function):
def _protect(*args, **kw):
user = globals().get('user')
if user is None or role not in user.roles:
raise Unauthorized("I won't tell you")
return function(*args, **kw)
return _protect
return _protect
测试
tarek = User(('admin', 'user'))
bill = User(('user',))
class MySecrets(object):
@protect('admin')
def waffleRecipe(self):
print('user tons of butter!')
theseAre = MySecrets()
user = tarek
theseAre.waffleRecipe()
user = bill
theseAre.waffleRecipe()
上下文提供者
上下文装饰器确保函数可以运行在正确的上下文中,或者在函数前后运行一些代码,也就是设定并复位一个特定的执行环境。
例子:当一个数据项需要在多个线程之间共享时,就要用一个锁来保护它避免多次访问。这个锁可以在装饰器中编写:
from threading import RLock
lock = RLock()
def synchronized(function):
def _synchronized(*args, **kw):
lock.acquire()
try:
return function(*args, **kw)
finally:
lock.release()
return _synchronized
@synchronized
def threadSafe():
pass
上下文装饰器通常会被上下文管理器(with语句)代替