使用__slots__和@property

2021/10/12 python 共 1702 字,约 5 分钟

使用__slots__和@property

当我们创建好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

注意的是,上述这样先定义好类再绑定方法对另外一个实例是没有用的,如果想要对所有实例都有用,就要在定义类的时候定义好方法

__slots__

有时候我们定义好的类,不想外部输入太多属性,限制外部附加属性,就可以使用__slots__

比如,只允许对Student实例添加nameage属性。

为了达到限制的目的,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__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的

@property

@property简单来说就是把方法转换为属性调用。这样做的目的是使得方法可以既能检查参数,又可以用类似属性这样简单的方式来访问类的变量。也可以防止属性被修改。

一般来讲,会先定义好@property将方法转换为属性,然后利用@方法名字.setter给属性赋值。

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

要特别注意:属性的方法名不要和实例变量重名。例如,以下的代码是错误的:

class Student(object):

    # 方法名称和实例变量均为birth:
    @property
    def birth(self):
        return self.birth

这是因为调用s.birth时,首先转换为方法调用,在执行return self.birth时,又视为访问self的属性,于是又转换为方法调用,造成无限递归,最终导致栈溢出报错RecursionError

文档信息

Search

    Table of Contents