保藏本站 保藏本站
真钱棋牌网主页 - 软件测验 - 常用手册 - 站长东西 - 技能社区
主页 > python > 正文

主页 - PHP - 数据库 - 操作体系 - 游戏开发 - JS - Android - MySql - Redis - MongoDB - Win8 - Shell编程 - DOS指令 - jQuery - CSS款式 - Python - Perl

Access - Oracle - DB2 - SQLServer - MsSql2008 - MsSql2005 - Sqlite - PostgreSQL - node.js - extjs - JavaScript vbs - Powershell - Ruby

Python 装修器深化了解

讲 Python 装修器前,我想先举个比方,虽有点污,但跟装修器这个论题很恰当。

每个人都有的内裤首要功用是用来遮羞,可是到了冬季它无法为咱们防风御寒,咋办?咱们想到的一个办法便是把内裤改造一下,让它变得更厚更长,这样一来,它不只有遮羞功用,还能供给保暖,不过有个问题,这个内裤被咱们改形成了长裤后,尽管还有遮羞功用,但本质上它不再是一条真实的内裤了。所以聪明的人们创造长裤,在不影响内裤的前提下,直接把长裤套在了内裤外面,这样内裤仍是内裤,有了长裤后宝宝再也不冷了。装修器就像咱们这儿说的长裤,在不影响内裤作用的前提下,给咱们的身子供给了保暖的成效。

谈装修器前,还要先要了解一件事,Python 中的函数和 Java、C++不太相同,Python 中的函数能够像一般变量相同作为参数传递给别的一个函数,例如:

def foo():
  print("foo")

def bar(func):
  func()

bar(foo)

正式回到咱们的主题。装修器本质上是一个 Python 函数或类,它能够让其他函数或类在不需求做任何代码修正的前提下添加额定功用,装修器的回来值也是一个函数/类目标。它常常用于有切面需求的场景,比方:刺进日志、功用测验、业务处理、缓存、权限校验等场景,装修器是处理这类问题的绝佳规划。有了装修器,咱们就能够抽离出许多与函数功用自身无关的相同代码到装修器中并持续重用。归纳的讲,装修器的作用便是为现已存在的目标添加额定的功用。

先来看一个简略比方,尽管实践代码或许比这杂乱许多:

def foo():
  print('i am foo')

现在有一个新的需求,期望能够记录下函数的履行日志,所以在代码中添加日志代码:

def foo():
  print('i am foo')
  logging.info("foo is running")

假如函数 bar()、bar2() 也有相似的需求,怎样做?再写一个 logging 在 bar 函数里?这样就形成许多相同的代码,为了削减重复写代码,咱们能够这样做,从头界说一个新的函数:专门处理日志 ,日志处理完之后再履行真实的业务代码

def use_logging(func):
  logging.warn("%s is running" % func.__name__)
  func()

def foo():
  print('i am foo')

use_logging(foo)

这样做逻辑上是没问题的,功用是完结了,可是咱们调用的时分不再是调用真实的业务逻辑 foo 函数,而是换成了 use_logging 函数,这就破坏了原有的代码结构, 现在咱们不得不每次都要把本来的那个 foo 函数作为参数传递给 use_logging 函数,那么有没有更好的办法的呢?当然有,答案便是装修器。

简略装修器

def use_logging(func):

def wrapper():
    logging.warn("%s is running" % func.__name__)
return func()  # 把 foo 作为参数传递进来时,履行func()就相当于履行foo()
return wrapper

def foo():
  print('i am foo')

foo = use_logging(foo) # 由于装修器 use_logging(foo) 回来的时函数目标 wrapper,这条句子相当于 foo = wrapper
foo()          # 履行foo()就相当于履行 wrapper()

use_logging 便是一个装修器,它一个一般的函数,它把履行真实业务逻辑的函数 func 包裹在其间,看起来像 foo 被 use_logging 装修了相同,use_logging 回来的也是一个函数,这个函数的名字叫 wrapper。在这个比方中,函数进入和退出时 ,被称为一个横切面,这种编程办法被称为面向切面的编程。

@ 语法糖

假如你触摸 Python 有一段时间了的话,想必你对 @ 符号必定不陌生了,没错 @ 符号便是装修器的语法糖,它放在函数开端界说的当地,这样就能够省掉最终一步再次赋值的操作。

def use_logging(func):

def wrapper():
    logging.warn("%s is running" % func.__name__)
return func()
return wrapper

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

foo()

如上所示,有了 @ ,咱们就能够省去foo = use_logging(foo)这一句了,直接调用 foo() 即可得到想要的成果。你们看到了没有,foo() 函数不需求做任何修正,只需在界说的当地加上装修器,调用的时分仍是和曾经相同,假如咱们有其他的相似函数,咱们能够持续调用装修器来润饰函数,而不必重复修正函数或许添加新的封装。这样,咱们就提高了程序的可重复运用性,并添加了程序的可读性。

装修器在 Python 运用如此便利都要归因于 Python 的函数能像一般的目标相同能作为参数传递给其他函数,能够被赋值给其他变量,能够作为回来值,能够被界说在别的一个函数内。

*args、**kwargs

或许有人问,假如我的业务逻辑函数 foo 需求参数怎样办?比方:

def foo(name):
  print("i am %s" % name)

咱们能够在界说 wrapper 函数的时分指定参数:

def wrapper(name):
    logging.warn("%s is running" % func.__name__)
return func(name)
return wrapper

这样 foo 函数界说的参数就能够界说在 wrapper 函数中。这时,又有人要问了,假如 foo 函数接纳两个参数呢?三个参数呢?更有甚者,我或许传许多个。当装修器不知道 foo 到底有多少个参数时,咱们能够用 *args 来替代:

def wrapper(*args):
    logging.warn("%s is running" % func.__name__)
return func(*args)
return wrapper

如此一来,别管 foo 界说了多少个参数,我都能够完整地传递到 func 中去。这样就不影响 foo 的业务逻辑了。这时还有读者会问,假如 foo 函数还界说了一些关键字参数呢?比方:

def foo(name, age=None, height=None):
  print("I am %s, age %s, height %s" % (name, age, height))

这时,你就能够把 wrapper 函数指定关键字函数:

def wrapper(*args, **kwargs):
# args是一个数组,kwargs一个字典
    logging.warn("%s is running" % func.__name__)
return func(*args, **kwargs)
return wrapper

带参数的装修器

装修器还有更大的灵敏性,例如带参数的装修器,在上面的装修器调用中,该装修器接纳仅有的参数便是履行业务的函数 foo 。装修器的语法答应咱们在调用时,供给其它参数,比方@decorator(a)。这样,就为装修器的编写和运用供给了更大的灵敏性。比方,咱们能够在装修器中指定日志的等级,由于不同业务函数或许需求的日志级别是不相同的。

def use_logging(level):
def decorator(func):
def wrapper(*args, **kwargs):
if level == "warn":
        logging.warn("%s is running" % func.__name__)
elif level == "info":
        logging.info("%s is running" % func.__name__)
return func(*args)
return wrapper

return decorator

@use_logging(level="warn")
def foo(name='foo'):
  print("i am %s" % name)

foo()

上面的 use_logging 是答应带参数的装修器。它实践上是对原有装修器的一个函数封装,并回来一个装修器。咱们能够将它了解为一个含有参数的闭包。当我 们运用@use_logging(level=”warn”)调用的时分,Python 能够发现这一层的封装,并把参数传递到装修器的环境中。

@use_logging(level=”warn”)等价于@decorator

类装修器

没错,装修器不只可所以函数,还可所以类,比较函数装修器,类装修用具有灵敏度大、高内聚、封装性等长处。运用类装修器首要依托类的__call__办法,当运用 @ 办法将装修器附加到函数上时,就会调用此办法。

class Foo(object):
def __init__(self, func):
    self._func = func

def __call__(self):
print ('class decorator runing')
    self._func()
print ('class decorator ending')

@Foo
def bar():
print ('bar')

bar()

functools.wraps

运用装修器极大地复用了代码,可是他有一个缺陷便是原函数的元信息不见了,比方函数的docstring、__name__、参数列表,先看比方:

# 装修器
def logged(func):
def with_logging(*args, **kwargs):
print func.__name__   # 输出 'with_logging'
print func.__doc__    # 输出 None
return func(*args, **kwargs)
return with_logging

# 函数
@logged
def f(x):
"""does some math"""
return x + x * x

logged(f)

不难发现,函数 f 被with_logging替代了,当然它的docstring,__name__便是变成了with_logging函数的信息了。好在咱们有functools.wraps,wraps自身也是一个装修器,它能把原函数的元信息拷贝到装修器里边的 func 函数中,这使得装修器里边的 func 函数也有和原函数 foo 相同的元信息了。

from functools import wraps
def logged(func):
  @wraps(func)
def with_logging(*args, **kwargs):
print func.__name__   # 输出 'f'
print func.__doc__    # 输出 'does some math'
return func(*args, **kwargs)
return with_logging

@logged
def f(x):
"""does some math"""
return x + x * x

装修器次序

一个函数还能够一起界说多个装修器,比方:

@a
@b
@c
def f ():
  pass

它的履行次序是从里到外,最早调用最里层的装修器,最终调用最外层的装修器,它等效于

f = a(b(c(f)))

感谢阅览,期望能协助到我们,谢谢我们对本站的支撑!

Python中%r和%s的详解及差异
Python中%r和%s的详解%r用rper()办法处理目标%s用str()办法处理目标有些情况下,两者处理的成果是相同的,比方说处理int型目标。例一:print"Iam%dyearsold."%22p

python开发利器之ulipad的运用实践
介绍UliPad是一个国人开发的python轻量级编辑器,导向和灵敏的编程器。它如类浏览器,代码主动完结许多功用,如:HTML检查器,目录浏览器,导游等。

python Selenium爬取内容并存储至MySQL数据库的完结代码
前面我经过一篇文章叙述了怎样爬取CSDN的博客摘要等信息。一般,在运用Selenium爬虫爬取数据后,需求存储在TXT文本中,可是这是很难进行数据处理和

本周排行

更新排行

强悍的草根IT技能社区,这儿应该有您想要的! 友情链接:b2b电子商务
Copyright © 2010 ystekkfj.com. All Rights Rreserved  京ICP备05050695号