python学习笔记十

微信公众号: 点击蓝色字体小白图像与视觉进行关注

关于技术、关注yysilence00。有问题或建议,请公众号留言

下面主要讲装饰器


  • 整理知识,学习笔记
  • 发布日记,杂文,所见所想

#1.Decorator是什么

Python的修饰器的英文名叫Decorator,当你看到这个英文名的时候,你可能会把其跟Design Pattern里的Decorator搞混了,其实这是完全不同的两个东西。在认识装饰器之前,我们先来点感性认识,看一个Python修饰器的Hello World的代码。

def hello(fn):
    def wrapper():
        print("hello, %s" % fn.__name__)
        fn()
        print("goodby, %s" % fn.__name__)
    return wrapper


# @hello
# def foo():  #foo = hello(foo)
#     print("i am foo")
def foo():
    print("i am foo")
foo = hello(foo)#hello(foo)返回了wrapper()函数,所以,foo其实变成了wrapper的一个变量
foo() #foo()执行其实变成了wrapper()

输出:

hello, foo
i am foo
goodby, foo

你可以看到如下的东西:

  • 函数foo前面有个@hello的“注解”,hello就是我们前面定义的函数hello;
  • 在hello函数中,其需要一个fn的参数(这就用来做回调的函数);
  • hello函数中返回了一个inner函数wrapper,这个wrapper函数回调了-传进来的fn,并在回调前后加了两条语句。

#2.Decorator 的本质
对于Python的这个@decorator,当你在用某个@decorator来修饰某个函数func时,如下所示:

@decorator
def func():
    pass

其解释器会解释成下面这样的语句:

func = decorator(func)

了然,这不就是把一个函数当参数传到另一个函数中,然后再回调吗?是的,但是,我们需要注意,那里还有一个赋值语句,把decorator这个函数的返回值赋值回了原来的func。 根据《函数式编程》中的first class functions中的定义的,你可以把函数当成变量来使用,所以,decorator必需得返回了一个函数出来给func,这就是所谓的higher order function 高阶函数,不然,后面当func()调用的时候就会出错。 就我们上面那个hello.py里的例子来说,

@hello
def foo():
    print "i am foo"

其解释器会解释成下面这样的语句:

foo = hello(foo)

再回到我们hello.py的那个例子,我们可以看到,hello(foo)返回了wrapper()函数,所以,foo其实变成了wrapper的一个变量,而后面的foo()执行其实变成了wrapper()。知道这点本质,当你看到有多个decorator或是带参数的decorator,你也就不会害怕了。

#3.不带参数的装饰器

"""
python中的装饰器分为两类:函数装饰器和类装饰器。
"""
# 不带参数的装饰器。即@decorator

"""
@decorator
"""

# a decorator receives the method it's wrapping as a variable 'f'
def increment(f):
    # we use arbitrary args and keywords to
    # ensure we grab all the input arguments.
    def wrapped_f(*args, **kw):
        # note we call f against the variables passed into the wrapper,
        # and cast the result to an int and increment .
        return int(f(*args, **kw)) + 1
    return wrapped_f  # the wrapped function gets returned.
@increment
def plus(a, b):
    return a + b
#等价于
#def plus(a, b):
#    return a + b
#plus = increment(plus)

result = plus(4, 6)
if result == 11:
    print('good')

输出:

good

#4.带参数的装饰器

#带参数的decrorator

def makeHtmlTag(tag, *args, **kwds):
    def real_decorator(fn):
        css_class = " class='{0}'".format(kwds["css_class"]) if "css_class" in kwds else ""

        def wrapped(*args, **kwds):
            return "<" + tag + css_class + ">" + fn(*args, **kwds) + "</" + tag + ">"

        return wrapped

    return real_decorator


@makeHtmlTag(tag="b", css_class="bold_css")
@makeHtmlTag(tag="i", css_class="italic_css")
@makeHtmlTag(tag="c", css_class="usa_css")
def hello(): #hello = makeHtmlTag(tag="b", css_class="bold_css")((makeHtmlTag(tag="i", css_class="italic_css")(hello))
    return "style"
print(hello())

输出:

<b class='bold_css'><i class='italic_css'><c class='usa_css'>style</c></i></b>

上面可以写的更加复杂来表示前端语言的一种显示。

#5.一个Logging的Decorator

from time import sleep
from functools import wraps
import logging
logging.basicConfig()
log = logging.getLogger("retry")

def retry(f):
    @wraps(f)
    def wrapper_function(*args, **kwargs):
    #wrapper_function=wraps(wrapper_function)
        MAX_ATTEMPTS = 5
        for attempt in range(1, MAX_ATTEMPTS + 1):
            try:
                return f(*args, **kwargs)
            except:
                log.exception("Attempt %s/%s failed : %s",
                              attempt,
                              MAX_ATTEMPTS,
                              (args, kwargs))
                sleep(10 * attempt)
        log.critical("All %s attempts failed : %s",
                     MAX_ATTEMPTS,
                     (args, kwargs))
    return wrapper_function

counter = 0

@retry
def save_to_database(arg):
# save_to_database=retry(save_to_database)
    print("Write to a database or make a network call or etc.")
    print("This will be automatically retried if exception is thrown.")
    global counter
    counter += 1
    # 这将在第一次调用中抛出异常
    # 并且在第二次调用中工作正常(即重试)
    if counter < 2:
        raise ValueError(arg)
if __name__ == '__main__':
    save_to_database("Some bad value")

输出:

Write to a database or make a network call or etc.
This will be automatically retried if exception is thrown.
ERROR:retry:Attempt 1/5 failed : (('Some bad value',), {})
Traceback (most recent call last):
  File "D:/PycharmProjects/more_decorator.py", line 14, in wrapper_function
    return f(*args, **kwargs)
  File "D:/PycharmProjects/more_decorator.py", line 38, in save_to_database
    raise ValueError(arg)
ValueError: Some bad value
Write to a database or make a network call or etc.
This will be automatically retried if exception is thrown.

上述是怎么工作的:

  • 经过一次raise抛出异常被try捕获后,第二次就正常工作了。因为第二次没有抛出异常

#6.一个MySQL的Decorator

import umysql
from functools import wraps
  
class Configuraion:
    def __init__(self, env):
        if env == "Prod":
            self.host    = "coolshell.cn"
            self.port    = 3306
            self.db      = "coolshell"
            self.user    = "coolshell"
            self.passwd  = "fuckgfw"
        elif env == "Test":
            self.host   = 'localhost'
            self.port   = 3300
            self.user   = 'coolshell'
            self.db     = 'coolshell'
            self.passwd = 'fuckgfw'
  
def mysql(sql):
  
    _conf = Configuraion(env="Prod")
  
    def on_sql_error(err):
        print err
        sys.exit(-1)
  
    def handle_sql_result(rs):
        if rs.rows > 0:
            fieldnames = [f[0] for f in rs.fields]
            return [dict(zip(fieldnames, r)) for r in rs.rows]
        else:
            return []
  
    def decorator(fn):
        @wraps(fn)
        def wrapper(*args, **kwargs):
            mysqlconn = umysql.Connection()
            mysqlconn.settimeout(5)
            mysqlconn.connect(_conf.host, _conf.port, _conf.user, \
                              _conf.passwd, _conf.db, True, 'utf8')
            try:
                rs = mysqlconn.query(sql, {})
            except umysql.Error as e:
                on_sql_error(e)
  
            data = handle_sql_result(rs)
            kwargs["data"] = data
            result = fn(*args, **kwargs)
            mysqlconn.close()
            return result
        return wrapper
  
    return decorator
  
@mysql(sql = "select * from coolshell" )
def get_coolshell(data):
    ... ...
    ... ..

更多请扫码关注

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值