装饰器的用法比较简单,但是理解装饰器的原理还是比较复杂的,考虑到接下来的爬虫框架中很多用到装饰器的地方,我们先来讲解一下。

函数

我们定义了一个函数,没有什么具体操作,只是返回一个固定值

请注意一下缩进

def sample():
return 1
print(sample())

作用域

函数内部的变量和函数外的变量是不同的

我们看一下下面的例子,locals()和globals()方法会得到局部变量和全局变量

我们可以在函数中调用全局变量,但是无法在函数中改变全局变量的值

global_string = 'This is a global string!'
def sample():
local_string='This is a local string!'
print(locals())
print(globals())
sample()

内嵌函数

下面的inner函数执行时,由于x不是局部变量,函数会自动扩大搜索范围,找到outer函数中的x。

outer中的inner也是类似与一个变量,不过这个变量是在outer中定义的,所以会直接搜索到。

def outer():
x=1
def inner():
print(x)
inner()
outer()

函数也是对象

下面的add和sub是标准的函数,接受两个值,返回一个计算后的值。

在apply函数中,我们将一个函数名作为参数传递给了一个新的参数,函数名就是变量标签。

def add(x,y):
return x+y
def sub(x,y):
return x-y
def apply(func,x,y):
return func(x,y) print(apply(add,2,1))
print(apply(sub,2,1))

函数作为返回值

outer()返回的是一个内部函数变量标签

outer()()才会执行内部函数,不过这样不太合适

def outer():
print('-'*10)
def inner():
print('Inside inner')
return inner
h=outer()#这句话不会输出内容
h()#这句话才会输出

闭包

内部函数会记住外层作用域

def outer(x):
def inner():
print(x)
return inner
outer(1)()
outer(2)()

装饰器

装饰器其实就是将一个以函数作为参数并返回一个替换函数的可执行函数。

内部函数返回了一个函数的值+1,外部函数返回了内部函数名

外部函数以一个函数名作为变量传入内部函数

def outer(some_func):
def inner():
print('Before some_func!')
return some_func()+1
return inner
def sample():
return 1
decorated=outer(sample)#这只是内部函数名
print(decorated())

举个例子

假如有一个表示坐标的类,我们设置了两个函数对坐标进行加减计算

class Coordinate():
def __init__(self,x,y):
self.x=x
self.y=y
def __repr__(self):
return 'Coord: '+str(self.__dict__)
def add(a,b):
return Coordinate(a.x+b.x,a.y+b.y)
def sub(a,b):
return Coordinate(a.x - b.x, a.y - b.y)

但是上面两个方法没有边界检测的功能,返回的坐标值不一定在第一象限。

如果我们不想改变上面函数和传入坐标的基础上,来实现检测的功能,可以考虑如下做法:

def wrapper(func):
def checker(a,b):
if a.x<0 or a.y<0:
a=Coordinate(a.x if a.x>0 else 0,a.y if a.y>0 else 0)
if b.x<0 or b.y<0:
b = Coordinate(b.x if b.x > 0 else 0, b.y if b.y > 0 else 0)
ret=func(a,b)
if ret.x<0 or ret.y<0:
ret=Coordinate(ret.x if ret.x > 0 else 0, ret.y if ret.y > 0 else 0)
return ret
return checker
add=wrapper(add)
sub=wrapper(sub)
one = Coordinate(100, 200)
two = Coordinate(300, 200)
print(sub(one,two))
print(add(one,two))

更简单的用法@

我们可以在定义add和sub函数的时候,就使用@符号将wrapper方法作用到这个函数上

@wrapper
def add(a,b):
return Coordinate(a.x + b.x, a.y + b.y)
#上面的代码就相当于 add=wrapper(add)

我们再来看一个带参数的装饰器

def deco(arg=True):
if arg:
def _deco(func):
def wrapper(*args,**kwargs):
startTime=time.time()
func(*args,**kwargs)
endTime=time.time()
msecs=(endTime-startTime)*1000
print('-> elapsed time: %f ms'%msecs)
return wrapper
else:
def _deco(func):
return func
return _deco @deco(False)
def myFunc():
print('start myFunc')
time.sleep(0.6)
print('end myFunc') @deco(True)
def addFunc(a,b):
print('start myFunc')
time.sleep(0.6)
print('result is %d' %(a+b))
print('end myFunc') print('myFunc is '+myFunc.__name__)
myFunc()
print()
print('addFunc is '+addFunc.__name__)
addFunc(3,8)

内置装饰器

Python中有三个内置的装饰器,都是与class相关的,包括:

staticmethod:类静态方法,没有self参数,并可以在类不实例化的情况下调用

classmethod:接收的第一个参数不是self,而是cls(当前类的具体类型)

property:属性的意思,表示可以通过类示例直接访问。

#我们来看一下property的用法
class Foo():
def __init__(self,var):
self._var=var
@property
def var(self):
return self._var
@var.setter
def var(self,var):
self._var=var
foo=Foo('var 1')
print(foo.var)
foo.var='var 2'
print(foo.var)

【Python基础】装饰器的解释和用法的更多相关文章

  1. python基础——装饰器

    python基础——装饰器 由于函数也是一个对象,而且函数对象可以被赋值给变量,所以,通过变量也能调用该函数. >>> def now(): ... print('2015-3-25 ...

  2. python基础—装饰器

    python基础-装饰器 定义:一个函数,可以接受一个函数作为参数,对该函数进行一些包装,不改变函数的本身. def foo(): return 123 a=foo(); b=foo; print(a ...

  3. python 基础——装饰器

    python 的装饰器,其实用到了以下几个语言特点: 1. 一切皆对象 2. 函数可以嵌套定义 3. 闭包,可以延长变量作用域 4. *args 和 **kwargs 可变参数 第1点,一切皆对象,包 ...

  4. day5学python 基础+装饰器内容

    基础+装饰器内容 递归特性# 1.必须有一个明确的结束条件# 2.每次进入更深一层递归时,问题规模相比上次递归应有所减少# 3.递归效率不高 def run(n): print(n) if int(n ...

  5. Python自动化 【第四篇】:Python基础-装饰器 生成器 迭代器 Json & pickle

    目录: 装饰器 生成器 迭代器 Json & pickle 数据序列化 软件目录结构规范 1. Python装饰器 装饰器:本质是函数,(功能是装饰其它函数)就是为其他函数添加附加功能 原则: ...

  6. python基础-装饰器,生成器和迭代器

    学习内容 1.装饰器 2.生成器 3.迭代器 4.软件目录结构规范 一:装饰器(decorator) 1.装饰器定义:本质就是函数,用来装饰其他函数,即为其他函数添加附加功能. 2.装饰器原则:1)不 ...

  7. python基础 (装饰器,内置函数)

    https://docs.python.org/zh-cn/3.7/library/functions.html 1.闭包回顾 在学习装饰器之前,可以先复习一下什么是闭包? 在嵌套函数内部的函数可以使 ...

  8. python基础===装饰器@property 的扩展

    以下来自Python 3.6.0 Document: class property(fget=None, fset=None, fdel=None, doc=None) Return a proper ...

  9. <Python基础>装饰器的基本原理

    1.装饰器 所谓装饰器一般是对已经使用(上线)的函数增加功能. 但是因为一般的大公司的严格按照开放封闭原则(对扩展是开放的,对修改是封闭的),不会让你修改原本的函数. 装饰器就是在不改变原本的函数且不 ...

随机推荐

  1. 关于Go语言daemon启动的方法.

    昨天搞了个文件共享的小程序,遇见了意见蛋疼的事,就是启动之后终端不能关闭,不然程序也会随着关闭. 我的解决方法: nohup ./httpserver & nohup这个命令能够把程序放后台执 ...

  2. AssionShop开源B2C电子商务系统-(二)定单流程活动图状态图(转载)

    B2C系统的灵魂所在就是定单的流程了,下面展示下定单的最重要的两个动态图,一个是定单流程活动图.还有一个是简单的定单状态图.通过这两张图,基本可以 了解系统定单流的大概情况了啊.图画的只是初步的设想, ...

  3. unity, trail renderer gone black on iOS

    给物体加了个trail renderer,使用了Legacy Shaders/Transparent/Diffuse,并将颜色调成白色半透明.在编辑器里效果是对的,但在ios上真机测试变成黑色的.然后 ...

  4. 点滴积累【other】---存储过程删除所有表中的数据(sql)

    USE [QG_Mis24] GO /****** Object: StoredProcedure [dbo].[p_set1] Script Date: 07/18/2013 13:25:57 ** ...

  5. 点滴积累【C#】---C#实现上传word将路径保存到数据库,文件保存到服务器。并且按照名称读取服务器的word

    效果: 1. . . 数据库: 思路: 上传:先获取word物理地址,然后根据文件的类型判断,然后再保存到相应的文件夹下,再把路径插入到数据库中. 读取:首先根据输入的文件名字在数据库中查找出来文件的 ...

  6. 【转载】Oracle之内存结构(SGA、PGA)

    [转自]http://blog.itpub.net/25264937/viewspace-694917/ 一.内存结构 SGA(System Global Area):由所有服务进程和后台进程共享: ...

  7. codility上的问题(34) Fluorum 2014

    好久没写codility的题了.一来没时间,二来有的题目不太好分析.这个题比較有意思,我还没有给出很严格的证明.

  8. 1.Vector(向量容器)

    一.概述 Vectors 包含着一系列连续存储的元素,其行为和数组类似.访问Vector中的任意元素或从末尾添加元素都可以在常量级时间复杂度内完成,而查找特定值的元素所处的位置或是在Vector中插入 ...

  9. 大型跨境电商 JVM 调优经历

    前提: 某大型跨境电商业务发展非常快,线上机器扩容也很频繁,但是对于线上机器的运行情况,特别是jvm内存的情况,一直没有一个统一的标准来给到各个应用服务的owner.经过618大促之后,和运维的同学讨 ...

  10. oracle中查看正在运行的并行进程

    select count(*) from v$px_process a where a.STATUS='IN USE';