欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

python基础第十五课--OOP创建可管理的属性(property)(小白piao分享)

程序员文章站 2022-07-14 19:02:42
...

为类创建可管理的属性

概述:我们可以在实例属性的获取和设定上增加一些额外的功能,比如在设定时增加类型的检查

        解决方案:

                要自定义对属性的访问,一种简单的方式是将其定义为property,增加了对属性的类型检查:

class Person:
	def __init__(self,first_name):
		self.first_name = first_name
	
	#getter
	@property
	def first_name(self):
		return self._first_name
	
	@first_name.setter
	def first_name(self,value):
		if not isinstance(value,str):
			raise TypeError('Expected a string')
		self._first_name = value
	
	@first_name.deleter
	def first_name(self):
		raise AttributeError('Can`t delete attribute')

              上述代码中一共有三个相互关联的方法,三个方法必须名字相同,第一个是getter函数,将first_name设置为了property,并且附带绑定了两个可选方法setter和deleter方法,值的注意的是,如果没有设置property,是不能设置setter 和 deleter装饰器的 。
              property的本质就是是的修饰内容更像是一个属性(而非方法),通过对属性进行赋值和del处理会自动调用装饰器setter和deleter对应装饰的方法,实例如下:

#对上述例子进行操作:
pr = Person('小白piao')#调用setter
pr.first_name = '小白piao最sao'#调用setter
print(pr.first_name)#小白piao最sao   #调用getter
del pr.first_name # AttributeError:Can`t delete attribute
#如果上述例子中对pr.first_name = 250;会抛出TypeError:Expected a string
#由此,便实现了对属性类型的限定

              疑问:在__init__中为何是self.first_name = first_name,而不是self._first_name = first_name?
              原因:其实由于下方设置了装饰器,所以在构造时,构造中的赋值实际上也是调用了setter方法,定义类在前,所以后边可以直接在创建对象是调用setter,这没有问题;这么做的目的,是为了在所有地方的属性设置时,都可以进行类型检查。如果在构造函数中使用‘self._first_name = first_name’,那么此处便不会调用setter,自然不会进行类型检查,所以这样会造成判断类型的疏忽,并不是说没有其他方法完成类型的检测。这样做在一定程度了规避了代码的大量重复。

              同样也可以对已经存在的get和set、delete定义为property。

              讨论:实际上,property的作用是将一系列的方法进行绑定,实际上可以通过调用property属性中的fget,fset,fdel方法来完成上述操作,但实际上并不会专门去调这些方法,而是通过特殊的操作诸如赋值、打印、删除都会自动调用以上三种方法。

              其实有一点很重要,只有在确实需要在访问属性时完成一些额外的工作时,才会去想到使用property。因为:一、这样写语法会对其他程序员产生困扰,代码可读性不高;二、代码的运行会变慢,实际上每个装饰器都需要额外调用函数来完成装饰动作。三、不会给设计带来真正的好处。特别是以后决定对某个属性增加额外的处理步骤是,可以再不修改已有代码的情况下将这个属性提升为一个Property。

              property可以用来定义需要被计算的属性:

import math
class Circle:
	def __init__(self,radius):
		self.radius = radius
	@property
	def area(self):
		return math.pi * radius ** 2
	@property
	def perimeter(self):
		return 2 * math.pi * radius

circle = Circle(2)
print(circle.area)
print(circle.perimeter)

              property属性为我们提供了很多的使用的API,但是实际上,合理地使用它才是根本。不要一个类中都是property那会导致你的代码过度膨胀和丑陋,以至于不愿意读你写的代码,原因很简单,菜鸡看不明白。

相关标签: python基础 python