聊起装饰器,就不得不说python自带的多少个装饰器:
内容包蕴:
正文实例讲述了Python装饰器(decorator)定义与用法。分享给大家供我们参考,具体如下:
经常,访问类和实例属性的时候,将再次来到所蕴藏的相干值,也正是一贯和类(实例的)的__dict__交际。若果要正规那一个访问和设值格局的话,
1、@property
将某函数,做为属性使用
- 元类
- python 对象和类的绑定以及类措施,静态方法
- python 子类调用父类方法计算
- python 方法分析顺序MPRADOQ
- python定制类和魔法方法
- 至于用法__slots__
- @property使用
- 修饰器
什么是装饰器(decorator)
一种艺术是数据描述符,另1种正是python内置的数据描述符协议函数Property()。property是1种特别的值,访问它时会计算它的值。
@property 修饰,正是将艺术,变成3特质量来选取。
0、元类
元类就是类的类,所体现的极限思想正是1切皆对象。
image.png
有关深层次,待使用到在计算。
一句话来说的话,可以把装饰器驾驭为3个包装函数的函数,它一般将盛传的函数也许是类做肯定的处理,重临修改之后的对象.所以,大家能够在不修改原函数的基础上,在实践原函数前后执行其余代码.相比较常用的境况有日记插入,事务处理等.
性情的原型函数是property(getf=None,setf=None,delf=None,doc=None),函数的前四个参数分别对应描述符的__get__、__set__、__delete__方法。
class A():
@property
def pfunc(self):
return self.value
@pfunc.setter
def pfunc(self,value):
self.value = value
@property
def pfunc1(self):
print('this is property')
if __name__=="__main__":
A.pfunc = 9
print A.pfunc
A.pfunc1
一、python 对象和类的绑定以及类方式,静态方法
常见大家要动用三个类中的方法时,都亟需实例化该类,再展开调用,那类中
self 和 cls
有哪些意思,能或不能够不伊始化四个实例而直白调用类方法,对象方法和类措施,静态方法又有怎样关系。是本篇文章思虑的标题。
类的调用有以下三种方式:
>>>class Test:
... def func(self, message):
... print message
...
>>>object1=Test()
>>>x=object1.func
>>>x('abc')
abc
>>>t=Test.func
>>>t(object1,'abc')
abc
而是对于 t=Test.func 来说,变量名 t 是关乎到了类 Test 的func
方法的地址上,t是非绑定的,所以在调用t(object一, ‘abc’)
时,必须显式的将实例名与 self 关联,不然将会报出”TypeError: unbound
method func() must be called with Test instance as first argument (got
str instance instead)” 的荒谬。
装饰器
class Foo(object):
def __init__(self,name):
self._name=name
def getname(self):
return self._name
def setname(self,value):
self._name=value
def delname(self):
del self._name
name=property(getname,setname,delname)
参考学习
知情以下几点:
一、类默许的格局都是绑定对象的,而self参数也是指向该目的,未有实例化对象时,类中方法调用会出错,也关系到python自动传送self参数。
贰、若想不实例化而直接通过 类名.方法
来调用,要求钦定该情势绑定到类,如下,一要使用@classmethod
装饰器,2方法中第二个参数为cls,而不是self。
>>> class Foo(object):
... @classmethod #定义类方法要点1
... def foo(cls): #定义类方法要点2
... print 'call foo'
...
>>> Foo.foo()
call foo
>>> Foo().foo()
call foo
类也是指标,由此和底下的静态方法照旧有不平等。类中央直机关接定义的习性如下,在类格局中也是足以一向运用的。
class pizza(object):
radius = 42
@classmethod
def get_radius(cls):
return cls.radius
print pizza.get_radius()
类方式对于开创工厂函数最有用,如下
class pizza(object):
def __init__(self,ingre):
self.ingre = ingre
@classmethod
def from_other(cls,fridge):
return cls(fridge.juice()+fridge.cheese())
def get_ingre(self):
return self.ingre
python主要知识点总计一,python自带的八个装饰器。cls代表此类,cls()也是用来成立对象,和pizza(fridge.juice()+fridge.cheese())效果同样。待理解,工厂方法是什么?
3、若只想当成二个惯常函数,定义不含有self和cls,则能够动用静态方法,如下:
>>> class Foo(object):
... @staticmethod
... def foo():
... print 'call foo'
...
>>> Foo.foo()
call foo
>>> Foo().foo()
call foo
作者:_Zhao_
链接:http://www.jianshu.com/p/4b871019ef96
來源:简书
最简便易行的函数,重临几个数的和
那样就能够对质量进行读取、设置和删除了:
二、@classmethod
修饰类的措施
2、python 子类调用父类方法总括
参考来源
talk is weak,从程序开首:
class Person(object):
def __init__(self):
self.name = "Tom"
def getName(self):
return self.name
class Student(Person):
def __init__(self):
self.age = 12
def getAge(self):
return self.age
if __name__ == "__main__":
stu = Student()
print stu.getName()
作者:nummy
链接:http://www.jianshu.com/p/dfa189850651
image.png
地方只是说澳优(Ausnutria Hyproca)个常用的子类调用父类场景,即调用父类的开首化函数。
直白运维以上代码会出错,因为纵然Student类继承了Person类,不过并不曾调用父类的init()方法,因为子类中对init函数实行了重写,若未有重写会壹直接轨父类的init函数自动运转。有以下三种艺术:
参考
1、super方法
class Base:
def __init__(self):
print('Base.__init__')
class A(Base):
def __init__(self):
# super().__init__()
super(A,self).__init__()
print('A.__init__')
class B(Base):
def __init__(self):
# super().__init__()
super(B,self).__init__()
print('B.__init__')
class C(A,B):
def __init__(self):
# super().__init__() # Only one call to super() here python3
super(C,self).__init__()
print('C.__init__')
运营结果
>>> c = C()
Base.__init__
B.__init__
A.__init__
C.__init__
>>>
二、调用未绑定的父类构造方法
class Person(object):
def __init__(self):
self.name = "Tom"
def getName(self):
return self.name
class Student(Person):
def __init__(self):
Person.__init__(self)
self.age = 12
def getAge(self):
return self.age
if __name__ == "__main__":
stu = Student()
print stu.getName()
作者:nummy
链接:http://www.jianshu.com/p/dfa189850651
非绑定方法不常常选择,上述情景却采用的可比多(即子类覆盖父类的点子)。运维时不曾父类person的实例,需求出示地开始展览传递,但有Student的实例,能够用来开展代替。
这种措施叫做调用父类的未绑定的构造方法。在调用二个实例的方法时,该办法的self参数会被电动绑定到实例上(称为绑定方法)。但假若直接调用类的点子(比如Person.__init),那么就一贯不实例会被绑定。那样就能够任意的提供应和必要要的self参数,那种措施称为未绑定unbound方法。
经过将日前的实例作为self参数提要求未绑定方法,Student类就能使用其父类构造方法的持有实现,从而name变量棉被服装置。
def calc_add(a, b):
return a + b
calc_add(1, 2)
>>> f=Foo('hello')
>>> f.name
'hello'
>>> f.name='world'
>>> f.name
'world'
>>> del f.name
>>> f.name
AttributeError: 'Foo' object has no attribute '_name'
带修饰类方法:cls做为方法的首先个参数,隐式的将类做为对象,传递给艺术,调用时毫不实例化。
三、python 方法分析顺序
而是今后又有新的急需,总括求和操作耗时,非常粗略,求和前得到一下日子,求和后再得到三次,求差即可
python2.6新增添了2个property装饰器,写起来尤其的幽雅。
常常函数方法:self做为第三个参数,隐式的将类实例传递给艺术,调用方法时,类必须实例化。
参考
上述博文具有很强的参照意义,转述如下:
在类的多继承中,方法分析顺序M奥迪Q5Q具有很要紧的意思,比如对以下菱形继承,D的实例调用show方法,是调用A的依然C的show。
image.png
python解析顺序的规范化也是2个穿梭进步的经过,首要有以下多个阶段:
- 2.二事先的经文类。经典类中多延续方法分析选用深度优先从左到右搜索,即D-B-A-C-A,相当于说经典类中只选取A的show方法。
- 经典类对单层继承未有怎么难点,不过对上述来说,我们精通更乐于使用C的show方法,因为她是对A的具体化,但是经典类比并不能够促成,于是在贰.第22中学引进新式类(继承自object),它依旧采取从左至右的吃水优先遍历,可是倘使遍历中冒出重复的类,只保留最终四个。并且在定义类时就总括出该类的
MRO 并将其当做类的质量。因而最新类能够平昔通过 mro 属性获取类的
MRO。
举个例子:
image.png
规行矩步深度遍历,其顺序为 [D, B, A, object, C, A,
object],重复类只保留最终2个,由此变成 [D, B, C, A, object]
那样看起来好像么分外,可是会有神秘的标题,比如破坏了单调性原则,由此在2.三中引入了
__ C3 算法__。
import datetime
def calc_add(a, b):
start_time = datetime.datetime.now()
result = a + b
end_tiem = datetime.datetime.now()
print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return result
calc_add(1, 2)
class Foo(object):
def __init__(self,name):
self._name=name
@property
def name(self):
return self._name
@name.setter
def name(self,value):
self._name=value
@name.deleter
def name(self):
del self._name
class A():
def func(self,x,y):
return x * y
@classmethod
def cfunc(cls,x,y):
return x * y
if __name__=="__main__":
print A().func(5,5)
print A.cfunc(4,5)
C3 MRQ
我们把类 C 的线性化(MRO)记为 L[C] = [python主要知识点总计一,python自带的八个装饰器。C1, C2,…,CN]。其中 C1 称为
L[C] 的头,别的成分 [C2,…,CN] 称为尾。即使2个类 C 继承自基类
B一、B二、……、BN,那么我们得以依照以下两步总括出 L[C]:
1、L[object] = [object]
2、L[C(B1…BN)] = [C] + merge(L[B1]…L[BN], [B1]…[BN])
那边的关键在于 merge,其输入是1组列表,根据如下格局出口3个列表:
www.5929.com,自作者批评第二个列表的头成分(如 L[B1] 的头),记作 H。
若 H
未出现在任何列表的尾巴,则将其出口,并将其从拥有列表中删除,然后回到步骤壹;不然,取出下1个列表的头部记作
H,继续该手续。
再度上述手续,直至列表为空或然无法再找出能够出口的因素。就算是前1种情景,则算法停止;如若是后壹种景况,表明不能够创设继承关系,Python
会抛出分外。
举例:
image.png
听他们讲C三,总括进度为:
image.png
现在呢,函数calc_diff(a, b)
,计算a-b,也想计算减法操作的光阴差,很好办,把那段代码复制过去.但是假若大家明日想编的是3个数学函数库,各样函数都想总计其实施耗费时间,总不可能三个一个复制代码,想个更加好的办法.
先是使用@property装饰器和相关办法将质量name设置为可读,前边的@name.setter和@name.deleter装饰器将别的艺术与name属性上的安装和
肆、python定制类和魔法方法
咱俩知晓,在Python中等高校函授数也是被视为对象的,能够看做参数字传送递,那么只要把总括耗费时间的独立为3个独立的函数calc_spend_time()
,然后把须要总括耗费时间的函数例如calc_add的引用传递给它,在calc_spend_time中调用calc_add,那样具有的内需总括耗费时间的函数都毫不修改自身的代码了.
删去操作相关联。实际的name值存款和储蓄在品质_name中。实际存款和储蓄属性的名目无需遵从任何约定,只须求与特征名称分裂即可。
3、@staticmethod
修饰类的方式
参照学习
形如__xxx__的变量恐怕函数名要小心,那个在Python中是有例外用途。常见的正是__inint__()函数了,在目的创立后用来开首化,类似的还有__new()__
和__del__函数。用的不是多多益善,不做细节深远。
def calc_spend_time(func, *args, **kargs):
start_time = datetime.datetime.now()
result = func(*args, **kargs)
end_tiem = datetime.datetime.now()
print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
def calc_add(a, b):
return a + b
calc_spend_time(calc_add, 1, 1)
# calc_spend_time(calc_add, a=1, b=2)
特色的施用服从统一访问规格。假若未有特色,将会以简练属性的花样拜访属性,而其余质量将以艺术的款式拜访。费劲去打听几时添加额外的()会带来不须求的模糊。
壹)是把函数嵌入到类中的一种格局,函数就属于类,同时申明函数不必要拜访这一个类
__str__ 和 __rerp__
class yuan(object):
def __init__(self):
self.name = 'yuanqijie'
self.age = 22
self.ambition = 'yes'
def __str__(self):
return 'object name: %s' % self.name
qijie = yuan()
print qijie
输出为:
object name: yuanqijie
若未有重写 __str__ 则输出为 <main.Student object at
0x109afb310>
但注意到,若直接出口变量而不是用print在提醒符下照旧上述消息,因为一贯展现变量调用的不是str(),而是repr(),两者的界别是str()重临用户看到的字符串,而repr()重返程序开发者看到的字符串,也正是说,repr()是为调节和测试服务的。能够接近上述方法实行重写,作为领悟即可。
看起来也不易,负责总括的函数不用更改,只需调用的时候作为参数传给总计时间差的函数.但就是那,调用的时候格局变了,不再是clac(1, 二),而是calc_spend_time(clac_add, 1,
2),万一calc_add大规模被调用,那么还得一处1处找,然后修改回复,如故很麻烦.倘使想不修改代码,就得使clac()
和calc_spend_time(clac)
功用等同,那么能够在calc_spend_time()
里把传播的clac包装一下,然后重临包装后的新的函数,再把再次回到的包装好的函数赋给clac,那么calc()的功效就和上例calc_spend_time(calc())
作用壹样.
骨子里,方法本人是作为一类特色被隐式处理的。
贰)使用修饰服,修饰方法,不需求实例化
5、__slots__
当定义三个类时,能够动态的给该类绑定二本性格和方法,比如:
>>> class Student(object):
... pass
>>> s = Student()
>>> s.name = 'Michael' # 动态给实例绑定一个属性
>>> print s.name
Michael
>>> def set_age(self, age): # 定义一个函数作为实例方法
... self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s, Student) # 给实例绑定一个方法
>>> s.set_age(25) # 调用实例方法
>>> s.age # 测试结果
25
在意的是,下面是给3个实例绑定的附和的措施,也正是说当在风谲云诡一个实例时,上述增添的性质和方法就不起成效了。能够给class绑定方法:
>>> def set_score(self, score):
... self.score = score
...
>>> Student.set_score = MethodType(set_score, None, Student)
只需将MethodType第四个参数改为None就行。
import datetime
def calc_spend_time(func):
def new_func(a, b):
start_time = datetime.datetime.now()
result = func(a, b)
end_tiem = datetime.datetime.now()
print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return new_func
def calc_add(a, b):
return a + b
calc_add = calc_spend_time(calc_add)
calc_add(1, 2)
class Foo(object):
def __init__(self,name):
self.name=name
def spam(self,x):
print '%s.%s'%(self.name,x)
__slots__ 用来界定属性
>>> class people(object):
... __slots__ = ('age','name') # 用tuple定义允许绑定的属性名称
...
>>> p = people()
>>> p.age = 20
>>> p.na = yuan
>>> p.na = 'yuan'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'people' object has no attribute 'na'
>>> p.name = 'yuan'
>>>
语法糖
用户创造f=Foo(‘hello’)那样的实例然后访问f.spam时,不会回到原始函数对象spam,相反会获得绑定方法。绑定方法有些类似于有个别总括的函数,
class A():
def func(self,x,y):
return x * y
@staticmethod
def sfunc(x,y):
return x * y
if __name__=="__main__":
print A.sfunc(6,5)
6、@property使用
参考
http://python.jobbole.com/80955/
由地点一节能够领略,绑定属性时,能够自由修改属性值,比如
s = Student()
s.score = 9999
许多时候都急需对属性值举办判定,比如正负,大小范围等,壹般的话就必要写一个函数进行逻辑检查,比如:
class Student(object):
def get_score(self):
return self._score
def set_score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
诸如此类就能担保能对传播的值实行逻辑约束,不过每一趟设置要求调用相应函数,比如s.set_score( 99 )
,又显得不是很简短,能还是不能够像
s.score = 99
相同简单又能举办逻辑检查呢。正是@property。
@property装饰器能够将2个method变为属性,能够像属性一样简单调用,如student.get_score
,若没有装饰器,则赶回的是函数地址。关于setter用法见下。
class Student(object):
@property
def score(self):
return self._score
@score.setter
def score(self, value):
if not isinstance(value, int):
raise ValueError('score must be an integer!')
if value < 0 or value > 100:
raise ValueError('score must between 0 ~ 100!')
self._score = value
@score.setter装饰器表示能够对该属性赋值,若未有则是二个只读的品质。
下边包车型大巴例子就是装饰器的概念,包装函数的函数.事实上下边包车型客车事例还可以够更简短
其间的self参数已经填入,但任何参数如故必要在使用()调用该函数时提供。那种绑定方法是由在后台执行的表征函数静静地创制的。使用@staticmethod和
7、修饰器
参考学习
import datetime
def calc_spend_time(func):
def new_func(a, b):
start_time = datetime.datetime.now()
result = func(a, b)
end_tiem = datetime.datetime.now()
print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return new_func
@calc_spend_time
def calc_add(a, b):
return a + b
calc_add(1, 2)
@classmethod定义静态方法和类措施时,实际上就钦点了动用差异的表征函数,以不一致的法子处理对这么些方法的拜访。
示例1:
class myDecorator(object):
def __init__(self, fn):
print "inside myDecorator.__init__()"
self.fn = fn
def __call__(self):
self.fn()
print "inside myDecorator.__call__()"
@myDecorator
def aFunction():
print "inside aFunction()"
print "Finished decorating aFunction()"
aFunction()
运转上述输出为:
inside myDecorator.__init__()
Finished decorating aFunction()
inside aFunction()
inside myDecorator.__call__()
@calc_spend_time
便是语法糖,它的面目正是:calc_add = calc_spend_time(calc_add)
Linux and
python学习交换一,二群已满.
示例2:
def check_is_admin(f):
def wrapper(*args, **kwargs):
if kwargs.get('username') != 'admin':
raise Exception("error occur")
return f(*args, **kwargs)
return wrapper
class store(object):
@check_is_admin
def get_food(self,username,food):
print food
s = store()
s.get_food(username='admin',food='noodles')
print s.get_food.__name__
上述程序定义了check_is_admin的装饰器,装饰器的首要作用是调用有些函数在此之前实施一类通用的操作,比如日志职分,上述是推行了权力检查。
函数棉被服装饰器修饰时,本质上函数变为
get_food = check_is_admin(get_food(self,username,food))
check_is_admin直接回到
wrapper函数地址,由此get_food也是指向wrapper函数,故print s.get_food.__name__
结果是
wrapper.
故而调用s.get_food(username='admin',food='noodles')
也就是
wrapper(username='admin',food='noodles')
。该函数最终一定要有return f(*args, **kwargs)
,那确认保障原来函数被执行并赶回结果。
因为装饰器使原函数指向了另1个函数(如上边的wrapper),而原函数只是该函数的一部分,该办法实在对原函数实行了扩充。但与此同时引进了其它的难题,原函数的性质和名字未有了,如上面s.get_food.__name__
并不是get_food。functools提供了名称叫wraps的装饰器,会复制那些属性给装饰器函数,用法如下:
import functools
def check_is_admin(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
if kwargs.get('username') != 'admin':
raise Exception("error occur")
#return f(*args, **kwargs)
return wrapper
只需额外添加两行代码。
值得1提的是,**kwargs内定了字典情势传入数据,因而只协理s.get_food(username=’admin’,food=’noodles’)而不扶助s.get_food(‘admin’,’noodles’)。为了代码的通用性,思量对其进行全面,使用inspect模块,最后为:
import functools
import inspect
def check_is_admin(f):
@functools.wraps(f)
def wrapper(*args, **kwargs):
func_args = inspect.getcallargs(f,*args,**kwargs)
if func_args.get('username') != 'admin':
raise Exception("error occur")
print 'test'
return f(*args, **kwargs)
return wrapper
func_args会以字典情势记录对应的key和value。意味着装饰器不用检查参数是或不是是基于地方的参数依旧根本字参数,最终以相同的格式保存在重临字典中。
无参数的函数装饰器
Linux and
python学习调换3群新开,欢迎参加,1起学习.qq 3群:5632278玖四
import datetime
def calc_spend_time(func):
def new_func(*args, **kargs):
start_time = datetime.datetime.now()
result = func(*args, **kargs)
end_tiem = datetime.datetime.now()
print "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return new_func
@calc_spend_time
def calc_add(a, b):
return a + b
@calc_spend_time
def calc_diff(a, b):
return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)
不前进,不倒退,结束的景色是绝非的.
注:
联机前行,与君共勉,
*args:把富有的参数按出现顺序打包成list
**kargs:把装有的key=value方式的参数打包成3个dict
带参数的函数装饰器
假使大家须求驾驭函数的一部分相当新闻,例如函数小编,能够透过给装饰器函数增添参数来完结.
import datetime
def calc_spend_time(author):
def first_deco(func):
def new_func(*args, **kargs):
start_time = datetime.datetime.now()
result = func(*args, **kargs)
end_tiem = datetime.datetime.now()
print author, "result:", result, "used:", (end_tiem - start_time).microseconds, "μs"
return new_func
return first_deco
@calc_spend_time('author_1')
def calc_add(a, b):
return a + b
@calc_spend_time('author_2')
def calc_diff(a, b):
return a - b
calc_add(a=1, b=2)
calc_diff(1, 2)
Python内置装饰器
Python内置的装饰器有四个:staticmethod,classmethod和property.
staticmethod:把类中的方法定义为静态方法,使用staticmethod装饰的办法能够使用类也许类的实例对象来调用,不供给传入self
class Human(object):
"""docstring for Human"""
def __init__(self):
super(Human, self).__init__()
@staticmethod
def say(message):
if not message:
message = 'hello'
print 'I say %s' % message
def speak(self, message):
self.say(message)
Human.say(None)
human = Human()
human.speak('hi')
输出:
I say hello
I say hi
classmethod:把类中的方法定义为类格局,使用classmethod装饰的措施能够使用类只怕类的实例对象来调用,并将该class对象隐式的作为第1个参数字传送入
class Human(object):
"""docstring for Human"""
def __init__(self):
super(Human, self).__init__()
self.message = '111'
def say(message):
if not message:
message = 'hello'
print 'I say %s' % message
@classmethod
def speak(cls, message):
if not message:
message = 'hello'
cls.say(message)
human = Human()
human.speak('hi')
输出同上例
property:把艺术成为属性
class Human(object):
"""docstring for Human"""
def __init__(self, value):
super(Human, self).__init__()
self._age = value
@property
def age(self):
return self._age
human = Human(20)
print human.age
越来越多关于Python相关内容可查阅本站专题:《Python数据结构与算法教程》、《Python
Socket编程技巧总括》、《Python函数使用技术计算》、《Python字符串操作技能汇总》及《Python入门与进阶经典教程》
仰望本文所述对大家Python程序设计有着支持。
您恐怕感兴趣的稿子:
- python怎么样定义带参数的装饰器
- 介绍Python的@property装饰器的用法
- Python中的各类装饰器详解
- 深深精晓python中的闭包和装饰器
- Python装饰器的函数式编制程序详解
- 详解Python中的装饰器、闭包和functools的学科
- 巧用Python装饰器
免去调用父类构造函数的难为 - Python中的多重装饰器
- python重试装饰器示例
- 实例讲解Python编程中@property装饰器的用法
- Python自定义装饰器原理与用法实例分析