3、动态绑定属性和方法

1、动态绑定属性和方法

正常情况下,当我们定义了一个class,创建了一个class的实例后,我们可以给该实例绑定任何属性和方法,这就是动态语言的灵活性。

#给对象绑定属性
class Student(object):
    def __init__(self):
        self.age=10
        self.score=90
s1 = Student()
s2 = Student()
s1.name = "liu"
print(s1.name)

#给对象绑定方法,但是只对当前实例起作用
def set_age(self,age):
    self.age = age

from types import MethodType
s1.set_age = MethodType(set_age,s1)
s1.set_age(25)
print(s1.age)

#给所有的实例都绑定方法
def set_score(self,score):
    self.score = score
Student.set_score = set_score
s2.set_score(100)
s1.set_score(200)
print("s2.score=%d" % s2.score)
print("s1.score=%d" % s1.score)

在这里插入图片描述

2、限制实例的属性

比如,只允许对Student实例添加name和age属性。为了达到限制的目的,Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性。

class Student(object):
    __slots__ = ('name','age')
s =Student()
s.name = 'liu'
s.age = 25
print(s.name)
print(s.age)
s.score = 99

在这里插入图片描述
但是要注意的是通过__slots__限制的属性只在父类种有效,在子类种是不起作用的。
如下所示:

class Student(object):
    __slots__ = ('name','age')
s =Student()
s.name = 'liu'
s.age = 25
print(s.name)
print(s.age)
class GraduaeStudent(Student):
    pass
g = GraduaeStudent()
g.score=100
print(g.score)

在这里插入图片描述
除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__

3、使用@property

在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改。而@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。如下:

class Student(object):
    pass
s1 = Student()
s1.score = 100
print(s1.score)

这显然不合逻辑。为了限制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 the integer')
        if value <0 or value >100:
            raise ValueError('score must between 0-100')
        self._score = value

s1 = Student()
s1.set_score(100)
print(s1.get_score())

在这里插入图片描述
但是上面的写法有点复杂,对外使用者而言还是不够完美,所以我们可以使用@property,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('the score must be integer')
        if value < 0 or value > 100:
            raise ValueError('the score must between 0-100')
        self._score = value

s =Student()
s.score = 101

下面的结果表示,对参数进行了检查。
在这里插入图片描述
所以我们注意到这个@property的时候,我们在对实例属性操作的时候,就知道该属性很可能不是直接暴露的,而是通过getter和setter方法来实现的。当我们没有设置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 2020-self._birth
s =Student()
s.birth = 1995
print(s.birth)
print(s.age)
s.age = 25

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值