Python装饰器

Python装饰器

简介

Python装饰器本质上是一个函数,它可以让其他函数不做代码变动的情况下,增加额外的功能,其返回值是增加功能后的新函数,可抽离出常用的修饰代码作为装饰器,增强了代码的可重用性.

装饰器

简单的装饰器
def foo():
  print "I am foo"

添加一个新的需求,输出关于该函数函数名的信息 –>

import logging

def foo():
  print "I am foo"
  logging.warning("foo is running")

现在有一新函数foo2也想实现该新需求 –>

import logging

def add_loginfo(func):
  logging.warning("%s is running"%func.__name__)
  func()

def foo2():
  print "I am foo2"

上述代码实现了需求,但改变了代码结构,原结构为调用foo2,如下:

import logging

def foo2():
  logging.warning("foo2 is runing")
  print "I am foo2"

在这可以用装饰器实现代码结构的保留:

#coding=utf-8
import logging

###########################
###
def add_loginfo(func):
  #参数是不确定的,所以用*args,*kwargs
  def wrapper(*args, **kwargs):
    logging.warning("%s is running"%func.__name__)
    return func(*args, **kwargs)
  return func(*args, **kwargs)
###
###########################

def foo2:
  print "I am foo2"

############################
###
foo2 = add_loginfo(foo2)
###
############################

foo2()

显然在实现新需求的同时,逻辑结构未发生改变
运行结果如下:

WARNING:root:foo2 is running
I am foo2

add_loginfo 函数 就可以提取成一个装饰器,如下:

import logging

def add_loginfo(func):
  #参数是不确定的,所以用*args,*kwargs
  def wrapper(*args, **kwargs):
    logging.warning("%s is running"%func.__name__)
    return func(*args, **kwargs)
  return wrapper

@add_loginfo
def foo():
  print "I am foo"

@add_loginfo
def foo2():
  print "I am foo2"

foo()
foo2()

运行结果如下:

WARNING:root:foo is running
I am foo
WARNING:root:foo2 is running
I am foo2
当装饰器的参数为类时:
#coding=utf-8
from functools import wraps

def singleton(cls):
  _instance = {}
  @wraps
  def _singleton(*args ,**kwargs):
    if cls not in _instance:
      _instance[cls] = cls(*args ,**kwargs)
    return _instance[cls]
  return _singleton

@singleton
class A(object):
  def __init__(self ,b):
    self.b = b

  def test(self):
    print self.b

a1 = A(1)
a2 = A(2)
print A.func_name
print type(A)
print type(a1)
print "a1:",id(a1)
print "a2:",id(a2)
a1.test()
a2.test()

这是利用装饰器实现的一个单例模式,类A传入装饰器后返回一个函数,此函数传入合适的参数能生成原先类的实例

运行结果如下:

A
<type 'function'>
<class '__main__.A'>
a1: 139648281857744
a2: 139648281857744
1
1
带参装饰器

带参装饰器可以用闭包实现
(闭包将在另一篇博文研究)

import logging

def add_loginfo(info):
  def decorator(func):
    def wrapper(*args, **kwargs):
      if info:
        print info
        logging.warning("%s is running"%func.__name__)
      return func(*args)
    return wrapper

  return decorator

@add_loginfo(info="FBI warning")
def foo(name):
  print "I am %s"%name

foo('wk')

运行结果如下:

FBI warning:
WARNING:root:foo is running
I am wk
元信息

函数经过装饰器后返回的是return出的函数,上述例子中为wrapper,自然,__doc__,__name__都变成wrapper的了,好在有functools.wraps,wraps本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中.

import logging
from functools import wraps

def add_loginfo(info):
  def decorator(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
      if info:
        print info
        logging.warning("%s is running"%func.__name__)
      return func(*args)
    return wrapper

  return decorator

@add_loginfo(info="FBI warning")
def foo(name):
  print "I am %s"%name

print foo.__name__
foo('wk')

运行结果如下:

foo
FBI warning:
WARNING:root:foo is running
I am wk
类装饰器

优点:灵活度大,高内聚,封装性强
实现:使用__init__传入目标,使用__call__调用目标

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

  def __call__(self):
    print "hello world"
    self.funcIn()

@Foo
def foo():
  print 'I am foo'

foo()

运行结果如下:

hello world
I am foo
常用装饰器
  1. “@classmethod”:声明类方法
  2. “@staticmethod”:声明静态方法
  3. “@property”:将类方法转换为只读属性和重新实现一个属性的setter和getter方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值