__slots__+@property将方法变成属性进行调用

#动态语言允许在定义完类并创建类的属性之后,可以给该实例绑定任何属性和方法
#定义class
class Student(object):
    pass
#创建实例
s=Student()
#绑定属性
s.name='Michale' 
print(s.name)  #Michale
#绑定方法
def set_age(self,age):
    self.age=age
from types import MethodType
s.set_age=MethodType(set_age,s)#将方法绑定到对象s上
s.set_age(24)
print(s.age)     #24
#-------------------------------------------------------------------------------------------------------#
#但是,给一个实例绑定的方法,对另一个实例是不起作用的,为了给所有实例都绑定方法,可以给class绑定方法
s2=Student()
#s2.set_age(34)
#print(s2.age)  #AttributeError: 'Student' object has no attribute 'set_age'
#----------------------------------------比较两种绑定方法------------------------------------------#
def set_score(self,score):
    self.score=score
flag=False
if flag==True:
    Student.set_score=set_score  #-----(1)这种绑定方法将属性绑定给每个实例,但是没有绑定到类上
    s.set_score(100)
    print(s.score)  #100
    s2.set_score(58)
    print(s.score,s2.score)  #  100  58
    #print(Student.score) #AttributeError: type object 'Student' has no attribute 'score' 

#--------(2)这种绑定方法将属性绑定给每个实例,同时也绑定到类上,并且保存的是最后一次的值  
else:
    Student.set_score=MethodType(set_score,Student)
    s.set_score(100)
    print(s.score)  #100
    s2.set_score(58)
    print(s.score,s2.score)  #  58  58
    print(Student.score)  #58--------(2)---------
#--------第(2)种绑定方法中,类属性是公共属性,所有实例都可以引用的,前提是实例自身没有同名的属性,
#因此类属性不能随意更改(别的实例可能在引用类属性的值)
def set_age(self,age):
    self.age=age
class Stu(object):
    pass
s=Stu()
a=Stu()
from types import MethodType
Stu.set_age=MethodType(set_age,Stu)  #将方法绑定到类上
a.set_age(15) #通过set_age方法,设置的类属性age的值
s.set_age(11) #也是设置类属性age的值,并把上个值覆盖掉
print(s.age,a.age) #由于a和s自身没有age属性,所以打印的是类属性age的值  11 11
a.age = 10  #给实例a添加一个属性age并赋值为10
s.age = 20  #给实例b添加一个属性age并赋值为20
#这两个分别是实例a和s自身的属性,仅仅是与类属性age同名,并没有任何关系
print(s.age,a.age)  #打印的是a和s自身的age属性值,不是类age属性值  20  10
#-------------------------------------------------------------------------------------------------------#
#--------如果我们想要限制实例的属性,例如,Student只能有属性name和age
#Python允许在定义class的时候,定义一个特殊的__slots__变量,来限制该class实例能添加的属性(注意,此处是实例属性)
class Student2(object):
    __slots__=('name','age') # 用tuple定义允许绑定的属性名称
s=Student2()
s.name='Michale'
print(s.name)  #Michale
s.age=34
print(s.age)   #34
#s.score=45
#print(s.score)  #AttributeError: 'Student2' object has no attribute 'score'
#------------------slots不能限制类属性的添加------------------#
def set_city(self, city):
    self.city=city
class Student3(object):
    __slots__ = ('name', 'age', 'set_city')    
    pass
#--------(1)添加实例属性  不可以-------#
if flag==True:
    Student3.set_city=set_city
    b = Student3()
    b.set_city('Beijing')
    print(b.city)   #AttributeError: 'Student3' object has no attribute 'city'  
#--------(2)添加类属性  可以-------#
else:
    Student3.set_city = MethodType(set_city, Student3)
    a = Student3()
    a.set_city('Beijing')
    print(a.city)  #Beijing
#-------------------------------------------------------------------------------------------------------#
#-------使用__slots__要注意,__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
class GraduateStudent(Student2):
    pass
g=GraduateStudent()
g.score=56
print(g.score)  #56
#除非在子类中也定义__slots__,这样,子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
class GraduateStudent(Student2):
    __slots__=('address')
g=GraduateStudent()
#g.score=56
#print(g.score)  #AttributeError: 'GraduateStudent' object has no attribute 'score'
g.address='Beijing'
print(g.address)  #Beijing
#--------------------------------------------@property---------------------------------------------------#
#在绑定属性时,如果我们直接把属性暴露出去,虽然写起来很简单,但是,没办法检查参数,导致可以把成绩随便改
#为了限制score的范围,可以通过一个set_score()方法来设置成绩,再通过一个get_score()来获取成绩
#在set_score()方法里,就可以检查参数
class Student4(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
s=Student4()
#s.set_score(9999)#ValueError: score must between 0 ~ 100!
s.set_score(60)
print(s.get_score())   #60
#---------既能够检查参数,又能够用类似属性这样简单的方式来访问类的变量
#---------@property装饰器就是负责把一个方法变成属性调用,同时还可以进行参数检查--------------#
class Student5(object):
    @property
    def score(self):
        return self._score #注意:此处的变量名_score必须和函数名score不重复,可以是score1等~
    @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
#把一个getter方法变成属性,只需要加上@property就可以了
#此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
s=Student5()
s.score=57
print(s.score)   #57
#------还可以定义只读属性,只定义getter方法,不定义setter方法就是一个只读属性,如下的birth是可读可写的,age是只读的
class Student6(object):
    @property
    def birth(self):
        return self._birth
    @birth.setter
    def birth(self,value):
        self._birth=value
    @property 
    def age(self):
        return 2017-self._birth
s=Student6()
s.birth=1992
print(s.birth)  #1992
#s.age=45  #AttributeError: can't set attribute
print(s.age)    #25


class Screen(object):
    def isint(self,value):
        if not isinstance(value,int):
            raise ValueError('value must be an integer!')
        if value<0:
            raise ValueError('value must be an positive integer!')

    @property
    def width(self):
        return self._width
    @width.setter
    def width(self,value):
        self.isint(value)
        self._width=value
    @property
    def height(self):
        return self._height
    @height.setter
    def height(self,value):
        self.isint(value)
        self._height=value
    @property
    def resolution(self):
        return self._height*self._width
scr=Screen()
scr.width=1024
scr.height=768
print(scr.width,scr.height,scr.resolution)  #1024 768 786432
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值