|
马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
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
复制代码
|
|