Python高级语法

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语句)代替

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值