马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
本帖最后由 heidern0612 于 2018-12-26 19:49 编辑
写心得的过程都是自我思考的过程,借鉴了很多论坛前辈和互联网大佬的经验,仓促间难免出错,如有错误,恳请指出,感激不尽。
网上扒了一大堆关于@property的文章,算是有点小感悟,趁热打铁写下来。
(此文主要借鉴了廖雪峰大神blog中关于@property一章节:戳我前进)。
以及CSDN里关于@property的一篇文章:戳我前进
主要写几个自己认知过程中的重点:
1、@property的作用:
A、将类方法转换为只读属性;
B、重新实现一个属性的setter和getter方法;
2、@property的简单使用介绍:
如果在一个类中要设置和获取一个成员变量的话,正常的写法应该是以下这种经典的写法。
class Student(object):
__slots__ = ('__name', '__age', '__score')
def __init__(self, name, age, score = 0):
self.__name = name
self.__age = age
self.__score = score
def getscore(self): # 获取score
return self.__score
def setscore(self, score): # 设置score value
if not isinstance(score, int):
raise ValueError('Score必须是int类型!')
if score < 0 or score > 100:
raise ValueError('Score值必须在0=<score<=100')
self.__score = score
在实际的应用过程中,如果要get/set score就得如下这种写法:
stu = Student('Wuli', 28)
stu.setscore(88)
stu.getscore() = 88
这样这样写本没有什么错, 但是鉴于在实际的码code的过程中,getfuncname/setfuncname实在是太普通了。
我们可能希望get/set一个值时有更简单的方法(如下),像设置成员变量一样去设置一个变量,又可以检查类型参数,如下:
#设置成员变量
stu.score = 100
#获取成员变量值
stu.score
# 报错:
AttributeError Traceback (most recent call last)
<ipython-input-9-fb8376649a7b> in <module>()
----> 1 stu.__score = 88
AttributeError: 'Student' object has no attribute '__score'
还真可以,因了python有@property 装饰器。我们对前面的代码稍稍做一些修改。
class Student(object):
__slots__ = ('__name', '__age', '__score')
def __init__(self, name, age, score = 0):
self.__name = name
self.__age = age
self.__score = score
# 获取score
@property
def score(self):
return self.__score
# 设置score value
@score.setter
def score(self, score):
if not isinstance(score, int):
raise ValueError('Score必须是int类型!')
if score < 0 or score > 100:
raise ValueError('Score值必须在0=<score<=100')
self.__score = score
注意一下第1段代码与第2段代码之间的差异, get/set的函数名都变成一样了。
但是上了分别多了一个@property/@score.setter.
@property 加了这个装饰器的funcname相当于getfuncname()
@score.setter 加了这个装饰器的funcname相当于setfuncname
自此,你就可以像耍成员变量一样的去耍它们了。
In [15]: stu = Student('wuli2', 28)
In [16]: stu.score = 88
In [17]: print(stu.score)
88
3、@property如何将类方法定义成只读?
如下,只定义getter方法,不定义setter方法就是一个只读属性:
class Student(object):
@property
def birth(self):
return self._birth
@birth.setter
def birth(self, value):
self._birth = value
@property
def age(self):
return 2015 - self._birth
这里的self.age实例化后属性就无法进行修改或设置。
上述关于介绍@property的代码中出现了:
__slots__ = ('__name', '__age', '__score')
这个__slot__是个什么意思呢?
slots的作用一:阻止在实例化类时为实例分配dict,节省内存空间。。
python中新模式的class,即从object继承下来的类有一个变量是__slots__。
在默认情况下每个类都会有一个dict,通过__dict__访问,这个dict维护了这个实例的所有属性,
例如:
class Base(object):
v = 1
def __init__(self):
pass
b = Base()
print (b.__dict__)
b.x = 2
print (b.__dict__)
可见:实例的dict只保持实例的变量,对于类的属性是不保存的,类的属性包括变量和函数。
由于每次实例化一个类都要分配一个新的dict,因此存在空间的浪费,因此有了slots。
当定义了slots后,slots中定义的变量变成了类的描述符,类的实例只能拥有这些个变量,而不在有dict,因此也就不能在增加新的变量。
如果你实在不能理解上面一大坨,你可以简单的理解为:当类被大量实例化的时候,__slot__可以不为实例化分配字典,节省了内存空间。
slots的作用二:限制该class能添加的属性。
class Student(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
s= Student ()
s.name = "John"
s.age = 30
s.score = 35
如以上代码,如果不添加最后一句s.score = 35,代码是可以正常运行的。
但如果添加了最后一句,就会抛出个AttributeError的错误,提示你Student类没有score属性。
另外,需要注意的是,,__slots__定义的属性仅对当前类起作用,对继承的子类是不起作用的。
除非在子类中也定义__slots__,这样,子类允许定义的属性就是自身的__slots__加上父类的__slots__。
如下代码运行是没有错误的。
class StudentA(object):
__slots__ = ('name', 'age') # 用tuple定义允许绑定的属性名称
class StudentB(StudentA):
__slots__ = ('score')
s= StudentB ()
s.name = "海顿上校"
s.age = 30
s.score = 35
|