Python中的装饰器与类

如何使用装饰器

当我们之前写好了一个程序,等过了几天发现这个函数不完整,又因为函数已经发布出去,无法更改的时候,我们是否会想这世上是否有后悔药,上帝能不能再给我重来一个的机会?别急,你是否经历过打开过套娃,分分钟逼死强迫症有没有。


那么,既然现实中有套娃,Python是否也会有类似套娃的函数呢,当通过外部函数(也就是大盒子)访问内部函数(也就是小盒子)并且将后面需要添加的内容放在大盒子内、小盒子外,这就是Python中的装饰器了。

那么,装饰器(本质上就是返回函数的函数)又是怎么具体使用的呢?让我们一起来看一看

例一:

import functools#0
def metric(func):#1
	@functools.wraps(func) #3 
	def wrapper(*args,**kw):#4
		print('hi'); #5
		return func(*args,**kw);#6
	return wrapper ; #2

@metric #7
def Hello():
    print('大家好,我是渣渣辉')
a = Hello()


从上面的例子我们可以看出对于Hello()函数这个小箱子,需要做的几个步骤。

首先需要做一个准备工作,也就需要导入functools模块,在这个模块中包含了装饰器。

需要先定义外部函数(也就是大箱子),然后在大箱子中返回一个函数A(也就是大箱子和小箱子中间的空间),然后在函数A中定义要添加的语句(也就是要放的东西)。

注意:*args是可变参数也就是参数的数目是可变的(可变参数在调用时自动组装为一个tuple),**kw是关键字参数,其允许你为函数添加新的参数名,并将其组装为一个dict。一个是参数名(相当于在定义()里面添加了新的参数名),一个是参数(也就是在‘:’后面的已经语句当中的变量)

例二

import functools#0
def log(text):#1
    def decorator(func):#3
        @functools.wraps(func) #4 
        def wrapper(*args, **kw):#6
            print('%s %s():' % (text, func.__name__))#7
            return func(*args, **kw)#8
        return wrapper#5
    return decorator#2

@log('qwer') #9
def Hello():
    print('大家好,我是渣渣辉')
	
a = Hello();


类:

__name__这种前后都带有两个下划线的称之为特殊方法。这种特殊方法要求用户在创建实例的时候,必须把__name__中强制把类型的参数输入进去,否则会报错。

class person(object):
	def __init__( self , age , gender ):
		self.age = age ;
		self.gender = gender ;

Liming = person( 16 , 'male' );
print( Liming.age )
print( Liming.gender )

输出为


说明,对于类,都有着继承的关系,而(object)的意思就是从哪里继承来的,如果没有继承的话,其就代表默认值。

对于__init__方法的self,其表示产生的实例本身,在调用参数的时候Python会自动将其读入,而且对于必备的参数,self都会将其传入进去,调用的时候只需使用Liming.age就可以了。另外需要说明的一点是,str类型必须加双引号""或单引号''

对于方法和普通的函数,其仅有的区别就是类中的方法第一个参数永远是实例变量self

私有变量:

私有变量即这个变量对于实例对象私有的,不能被随意的改变,这样就避免了变量可以被肆意修改的恶果。

__age 这种前面有两个下划线的是‘私有变量’,即不能直接通过  实例变量.__age 来访问,但可以通过   实例对象._类名__age   来访问(最好不要这么做)

_year这种前面只有一个下划线的默认为是‘私有变量’,虽然还可以直接通过._year来访问,但是最好不要这么做。

class person(object):
	def __init__( self , age , gender ):
		self.__age = age ;
		self._gender = gender ;

Liming = person( 16 , 'male' );
print( Liming._person__age )
print( Liming._gender )
print( Liming.__age )
输出为


那么,当我们想修改实例变量的时候,发现其不能修改,这不是失去了其应有的效果了么?别急,Python在为我们关上一扇门的同时,又为我们打开了一扇门。get_变量  和 set_变量 就为我们提供了得到和修改变量的机会,让我们来一起看一看吧。

class person(object):
	def __init__( self , age , gender ):
		self.__age = age ;
		self.__gender = gender ;
	def get_age( self ):
		return self.__age ;
	def get_gender( self ):
		return self.__gender ;
	def set_age( self , age ):
		self.__age = age ;
	def set_gender( self , gender ):
		if not isinstance( gender , str ):
			raise TypeError( '您输入的不是字符串,请重新输入' );
		elif gender == 'male' or gender == 'female':
			self.__gender = gender ;

Liming = person( 16 , 'male' );
print( Liming.get_age() )
print( Liming.get_gender() )
Liming.set_gender( 'female' );
print( Liming.get_gender() )

通过set_变量 方法,我们可以完成在一定条件下的更改实例变量值的操作,从而在一定程度上限制了用户的错误操作。

注意,输出的时候,Liming.get_gender()若是省去了括号,就会输出这个方法的内存地址

类中的装饰器@property:

上面的类的调用是不是略显复杂呢?对于用户来说,要输入的东西太多并不是一件好事,还记得前面学过的装饰器么?那么装饰器这个大箱子是否又能放到类中去呢?答案是肯定的,那么现在就让我们一起来学习@property装饰器吧

class person(object):
	def __init__( self , age , gender ):
		self.__age = age ;
		self.__gender = gender ;
	def get_age( self ):
		return self.__age ;
	@property
	def gender( self ):
		return self.__gender ;
	def set_age( self , age ):
		self.__age = age ;
	@gender.setter
	def gender( self , val ):
		if not isinstance( val , str ):
			raise TypeError( '您输入的不是字符串,请重新输入' );
		elif val == 'male' or val == 'female':
			self.__gender = val ;

Liming = person( 16 , 'male' );
print( Liming.get_age() )
print( Liming.gender )
Liming.gender ='female';
print( Liming.gender )

输出为


怎么样,是不是很神奇?仅仅通过两行短代码就实现了用户端的极短调用,现在就让我们来看一看@property装饰器做了什么吧。

首先@property把gender变成了一个类的属性,也就是使得用户可以通过调用属性的方式来调用gender函数,但是这个属性仍然是只可读的;然后@gender.setter相当于把其下面的gender函数变成了属性赋值语句,也就是说这个属性可以被赋值了。

注意 属性的赋值需要借用‘=’而方法、函数的传递参数需要借用()!!!

类中的方法与函数与属性

class person(object):
	identity = 'student' ;
	pass;

在上述例子中,我们定义了person这个类的identity属性,在实例化类的过程中,这个类的属性也会传递给实例化对象,但是当通过重新赋值之后,实例属性的优先级将会高于类属性的优先级,只有当实例属性被删除后,类属性才会被显露出来。

class person(object):
	identity = 'student' ;
	pass;


Liming = person();
print( Liming.identity );
Liming.identity = 'lawyer';
print( Liming.identity );
print( person.identity );
del Liming.identity;
print( Liming.identity );
输出示意:


牢记  实例属性>类属性,即实例会覆盖类的属性

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值