您现在的位置是:首页 > 正文

Python中的内置装饰器之property

2024-04-01 00:27:30阅读 1

装饰器是Python中很重要的一个概念,但是这篇文档不介绍装饰器的实现,我们只需要知道装饰器可以实现一些功能;

Python中也包含一些自带的装饰器,这次就说一下属性装饰器property

相关知识点


Python中的实例属性和私有属性

用法


property装饰器的作用是让一个类方法的访问方式变成属性的访问方式,用法如下:

class Num:

	@property
    def x(self):
        return '用类方法定义,用property装饰的x'

a = Num()  # 把C实例化,命名为a
print(a.x)  # 我们访问了a实例的x方法,但是没有对x做调用,和访问实例属性的方法一样

输出:用类方法定义,用property装饰的x

作用


使用这种方式来定义实例属性,我们就可以在类属性x中对x做一定的校验,这一点我们在后面再说。

衍生装饰器


举一个数字相加的例子:

class Num:

    @property
    def x(self):
        return 1

    @property
    def y(self):
        return 2

    def printf(self):
        print(f'{self.x}加{self.y}的和是:{self.x+self.y}')

a = Num()  # 把C实例化,命名为a
a.printf()

这个例子和上面的例子一样,我们定义了属性x和y,输出了x+y的和

这个例子的输出是:1加2的和是:3

这个时候我们希望可以在外部修改x的值,就会发现无法修改,因为本质上x是一个方法,而不是类属性:

 class Num:
 
	@property
	def x(self):
         return 1
 
	@property
	def y(self):
		return 2
 
	def printf(self):
		print(f'{self.x}加{self.y}的和是:{self.x+self.y}')
 
a = Num()  # 把C实例化,命名为a
a.x = 2
print(a.x)

输出:AttributeError: can't set attribute

所以我们需要另外在类中定义一个方法,来修改x的值,相当于给外部创建一个API接口,让外部通过这个API来修改,这就用到了setter装饰器:

setter装饰器

用法

为了可以修改x,我们把x的值1写成实例属性self.num,

当然这个例子中外部也可以直接通过修改num的值来修改x的值,不过这个不要紧,因为只是为了方便理解,

实际使用中我们可以把self.num 写成私有属性,来保障不会被外部直接修改值,

写一个x属性同名方法,并且用x属性同名的setter装饰器(x.setter)来装饰同名方法x,然后在这个方法下实现对self.num的值的修改:

class Num:

	def __init__(self):
		self.num = 1
 
	@property
	def x(self):
		return self.num
 
	@x.setter
	def x(self, item):
		self.num = item
 
	@property
	def y(self):
		return 2

	def printf(self):
		print(f'{self.x}加{self.y}的和是:{self.x+self.y}')

a = Num()  # 把C实例化,命名为a
a.x = 2
a.printf()

输出:2加2的和是:4

这样我们就可以通过a.x = 2来给self.num重新赋值,这样做的好处是不改变外层修改x值的方式,来实现对property属性的修改,这也是让代码更高可用,更可读很重要的一点。

deleter装饰器

用法

同setter装饰器,不再详细说明,不同的地方在于被deleter装饰的同名x方法不接收参数,因为我们只是删除了self.num,不需要接收参数:

class Num:

	def __init__(self):
		self.num = 1

	@property
	def x(self):
		return self.num

	@x.setter
	def x(self, item):
		self.num = item

	@x.deleter
	def x(self):
		del self.num

	@property
	def y(self):
		return 2

	def printf(self):
		print(f'{self.x}加{self.y}的和是:{self.x+self.y}')

a = Num()  # 把C实例化,命名为a
a.x = 2
a.printf()
del a.x
print(a.x)

输出:
2加2的和是:4
AttributeError: 'Num' object has no attribute 'num'

deleter装饰器装饰的方法就可以被使用del 来删除对应的属性,删除属性的操作我们就再同名方法x中进行了实现,

这样外部删除属性的方法也和删除一个属性的方法保持一致,同样保证了高可用性和可读性。

作用


现在可以说明文章一开始说的作用了,

我们通过这种property,setter,deleter装饰器的方式,把实例属性self.num写成property属性,我们就可以完成一个操作,

对外部修改、删除属性的操作,做进一步的过滤和限制

还是同样的例子,我们希望可以限制上层代码实例化并且修改x的值为非int类型,因为这会造成我们的求和方法报错,我们就可以通过这种方式实现:

class Num:

    def __init__(self):
        self.num = 1

    @property
    def x(self):
        return self.num

    @x.setter
    def x(self, item):
        if isinstance(item, int):
            self.num = item
        else:
            print('不要把非int类型赋值给x!!!')

    @property
    def y(self):
        return 2

    def printf(self):
        print(f'{self.x}加{self.y}的和是:{self.x+self.y}')

a = Num()  # 把C实例化,命名为a
a.x = '1234567'  # 突发奇想把x的值改为str类型

输出:不要把非int类型赋值给x!!!

综上,这样就可以保障上层在修改x的值的时候,可以被我们的同名装饰器x先做进一步校验,

当然你想要先对入参item做一些其他操作也一样可以,操作之后,再更改self.num为item,

这个时候printf 求和方法,就可以安全使用 + 运算符求和了。

总结


使用property装饰器装饰的方法可以被上层以调用属性的方式来调用,类本身也可以,可以理解为property属性,也是一个属性;

使用property属性同名.setter装饰器装饰的同名方法,提供property=xx 的方法;

使用property属性同名.deleter装饰器装饰的同名方法,提供del xx的方法。

另外,重要的一点是既然我们已经使用property来代替实例属性,那自然我们是不希望外层可以直接修改实例属性的,

既然如此我们就最好不能使用上述例子中使用的self.num的命名方式来定义实例属性,而是使用私有属性的方式来定义(关于私有属性的知识点可以查看文章开头的相关知识点):

class Num:

    def __init__(self):
        self.__num = 1

    @property
    def x(self):
        return self.__num

    @x.setter
    def x(self, item):
        if isinstance(item, int):
            self.__num = item
        else:
            print('不要把非int类型赋值给x!!!')

    @x.deleter
    def x(self):
        if self.__num:
            del self.__num
        else:
            print('属性不存在')

    @property
    def y(self):
        return 2

    def printf(self):
        print(f'{self.x}加{self.y}的和是:{self.x+self.y}')

a = Num()  # 把C实例化,命名为a
a.__name = 3  # 修改私有属性为3
a.printf()

这样外部就不能通过 a.__name = 3的方式来改变私有属性__name,如果需要修改,就要通过a.x = 3的“API”来修改,从而我们可以对“API入参”进行校验和处理。

网站文章

  • TextMeshPro使用说明 热门推荐

    TextMeshPro使用说明 热门推荐

    TextMeshPro使用说明创建字体所以对于中文环境建议Font Creator窗口属性注意要包含空格字符,除非确定你不需要它设置全局默认字体第一种方法第二种方法精灵字体动态字体扩展原理使用方法组件...

    2024-04-01 00:27:20
  • 大数据中的hbase是什么?有哪些特点?

    大数据中的hbase是什么?有哪些特点?

    与2018年夏季天气同样火爆的就属大数据了,作为一个可以敢和太阳肩并肩的新事物,大数据火爆、受人关注,在各个领域都有实际的应用。如今,无论是企业、商家还是个人对于大数据的关注都丝毫没有降低,那么对于大数据这个新兴高科技产物,你对hbase的了解有多少呢? 首先,我们从概念上了解什么是hbase HBase其实一个缩写,是Hadoop Database的简称,从问世之初,就为了解决用大量廉价...

    2024-04-01 00:26:56
  • 代码随想录训练营第III期--038--python

    代码随想录训练营第III期--038--python

    2024-04-01 00:26:49
  • 大厂程序员都在用VS Code远程开发工具,手把手教你配置,工作效率提高十倍

    大厂程序员都在用VS Code远程开发工具,手把手教你配置,工作效率提高十倍

    文章每周持续更新,原创不易,「三连」让更多人看到是对我最大的肯定。可以微信搜索公众号「 后端技术学堂 」第一时间阅读(一般比博客早更新一到两篇)今天和大家分享远程开发工具,分享一下我平常是如何用 VS...

    2024-04-01 00:26:42
  • 【2023.11 | github学生认证 | 解决没有proof type选项问题】

    【2023.11 | github学生认证 | 解决没有proof type选项问题】

    可能因为bug问题,根本找不到proof type选项。

    2024-04-01 00:26:17
  • 招人,我们是认真的 ——“阿里云-ECS/神龙计算平台” 急招开发

    招人,我们是认真的 ——“阿里云-ECS/神龙计算平台” 急招开发

    点击上方蓝色字体,关注我 ——一个在阿里云打工的清华学渣!图 by: 石头@阿里云北京办公场所前言招人,我们真的是认真的,看下面两篇“阿里云” 公众号的文章,虽有好几万的阅读,却并没收...

    2024-04-01 00:26:09
  • 计算出1+2+3+..+100的结果。可以使用多种方法解答。

    计算出1+2+3+..+100的结果。可以使用多种方法解答。

    计算1+2+3+...+100的结果。以下使用多种办法: 方法1:for...do...done的数值处理 方法1:for…do…done 的数值处理 sum=0 for ((i=1;i<=100;i++)) do ((sum+=$i)) done 其余各种方法,个人比较推荐第五种算法 1 方法2:for…do…done (固定回圈) 2...

    2024-04-01 00:26:03
  • Scala学习笔记(二)

    一、函数1. 定义函数// 用def关键字定义一个函数 // 格式 def 函数名(参数名 : 类型): 函数返回值的类型 = {}def main(args: Array[String]):...

    2024-04-01 00:25:56
  • 如何打包谷歌插件

    如何打包谷歌插件

    第一步 浏览器输入以下,按回车 chrome://version/ 找到 个人资料路径 复制 第二步 快捷键 win+e 把剪贴板中的粘贴到地址栏,按回车 找到这个文件夹 或者ctrl+f 输入Extensions按回车 第三步 浏览器进入chrome://extensions/ 选择要打包的插件 观察id 在第二步的文件夹中找到以上面id...

    2024-04-01 00:25:31
  • 如何创建一个Vue工程

    如何创建一个Vue工程

    (1)以管理员身份打开命令行界面,进入任意一个想要创建项目的文件夹,输入。如果出现版本号,说明我们成功安装了nodejs。出现以下版本号,说明我们的环境安装成功。(2)你的第一个vue项目页面就创建好...

    2024-04-01 00:25:24