数据信息封裝 、承继和多态仅仅面向对象编程设计中最基本的3个定义。在Python中 ,面向对象也有许多 高級特点 ,容许大家写成十分强劲的作用 。 大家会探讨多种承继 、定制类、元类等定义 。
应用__slots__

一切正常状况下,在我们界定了一个class,建立了一个class的实例后 ,我们可以给该实例关联一切属性和方式,这就是动态语言的协调能力。先界定class:

class Student(object):
    pass

随后,试着给实例关联一个属性:

>>> s = Student()
>>> s.name = 'Michael' # 动态性给实例关联一个属性
>>> print(s.name)
Michael

还能够试着给实例关联一个方式:

>>> def set_age(self, age): # 界定一个涵数做为实例方式
...     self.age = age
...
>>> from types import MethodType
>>> s.set_age = MethodType(set_age, s) # 给实例关联一个方式
>>> s.set_age(25) # 启用实例方式
>>> s.age # 检测結果
25

可是 ,给一个实例关联的方式,对另一个实例是失灵的:

>>> s2 = Student() # 建立新的实例
>>> s2.set_age(25) # 试着启用方式
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'set_age'

为了更好地给全部实例都关联方式,能够给class关联方式:

>>> def set_score(self, score):
...     self.score = score
...
>>> Student.set_score = set_score

给class关联方式后 ,全部实例均可启用:

>>> s.set_score(100)
>>> s.score
100
>>> s2.set_score(99)
>>> s2.score
99

一般状况下,上边的set_score方式能够立即界定在class中,但动态性关联容许我们在程序执行的全过程中动态性给class再加上作用 ,这在静态数据語言中难以完成。

应用__slots__

可是,如果我们要想限定实例的属性该怎么办?例如,只容许对Student实例加上name和age属性 。
为了更好地做到限定的目地 ,Python容许在界定class的情况下 ,界定一个独特的__slots__自变量,来限定该class实例能加上的属性:

class Student(object):
    __slots__ = ('name', 'age') # 用tuple界定容许关联的属性名字

随后,大家试一下:

>>> s = Student() # 建立新的实例
>>> s.name = 'Michael' # 关联属性'name'
>>> s.age = 25 # 关联属性'age'
>>> s.score = 99 # 关联属性'score'
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'

因为'score'沒有被放进__slots__中 ,因此 不可以关联score属性,尝试关联score将获得AttributeError的不正确。
应用__slots__要留意,__slots__界定的属性仅对当今类实例起功效 ,对承继的子类是失灵的:

>>> class GraduateStudent(Student):
...     pass
...
>>> g = GraduateStudent()
>>> g.score = 9999

除非是在子类中也界定__slots__,那样,子类实例容许界定的属性便是本身的__slots__再加上父类的__slots__。

应用@property

在关联属性时 ,如果我们立即把属性曝露出来,尽管写起來非常简单,可是 ,没法查验主要参数,造成 能够把考试成绩随意改:

s = Student()
s.score = 9999

这显而易见漏洞百出 。为了更好地限定score的范畴,能够根据一个set_score()方式来设定考试成绩 ,再根据一个get_score()来获得考试成绩 ,那样,在set_score()方式里,就可以查验主要参数:

class Student(object):

    def get_score(self):
         return self._score

    def set_score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

如今 ,对随意的Student实例开展实际操作,就不可以无拘无束地设定score了:

>>> s = Student()
>>> s.set_score(60) # ok!
>>> s.get_score()
60
>>> s.set_score(9999)
Traceback (most recent call last):
  ...
ValueError: score must between 0 ~ 100!

可是,上边的启用方式又稍显繁杂 ,沒有立即用属性那么立即简易。
有木有既能查验主要参数,又可以用相近属性那样简易的方法来浏览类的自变量呢?针对完美主义者的Python程序猿而言,它是务必要保证的!
你是否还记得装饰器(decorator)能够给涵数动态性再加上作用吗?针对类的方式 ,装饰器一样起功效。Python内嵌的@property装饰器便是承担把一个方式变为属性启用的:

class Student(object):

    @property
    def score(self):
        return self._score

    @score.setter
    def score(self, value):
        if not isinstance(value, int):
            raise ValueError('score must be an integer!')
        if value < 0 or value > 100:
            raise ValueError('score must between 0 ~ 100!')
        self._score = value

@property的完成非常复杂,大家先调查怎么使用 。把一个getter方式变为属性,只必须再加上@property就可以了 ,这时,@property自身又建立了另一个装饰器@score.setter,承担把一个setter方式变为属性取值 ,因此 ,大家就有着一个可控性的属性实际操作:

>>> s = Student()
>>> s.score = 60 # OK,具体转换为s.set_score(60)
>>> s.score # OK,具体转换为s.get_score()
60
>>> s.score = 9999
Traceback (most recent call last):
  ...
ValueError: score must between 0 ~ 100!

注意到这一奇妙的@property ,我们在对实例属性实际操作的情况下,就了解该属性很可能并不是立即曝露的,只是根据getter和setter方式来完成的。
还能够界定写保护属性 ,只界定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

上边的birth是可读写能力属性,而age便是一个写保护属性 ,由于age能够依据birth和获取当前时间推算出来。
总结
@property广泛运用在类的界定中,能够让调用者写成简洁明了的编码,另外确保对主要参数开展必需的查验 ,那样,程序执行时就降低了失败的概率 。

文章来源于网络,如有侵权请联系站长QQ61910465删除
本文版权归QU快排Www.seoGurubLog.com 所有,如有转发请注明来出,竞价开户托管,seo优化请联系QQ▲61910465