如何使用描述符对实例属性做类型检查?

需求:
在某项目中,我们实现了一些类,并希望能像静态语言那样(C,C++,Java)对它们的实例属性做类型检查
P = Person()
P.name = 'Bob' # 必须是str
P.age = 18 # 必须是Int
P.height = 1.83 # 必须是float

要求:
1、可以对实例变量名指定类型
2、赋予不正确类型时抛出异常

思路:
使用描述符实现需要类型检查的属性:分别实现__get__,set,__delete__方法,在__set__内使用isinstance函数做类型检查

class Attr(object):

    def __init__(self,name,type_):
        self.name = name
        self.type_ = type_
    
    def __get__(self,instance,cls):
        print('in __get__',instance,cls)
        return instance.__dict__[self.name]  # 将self.name变为实例P的属性

    def __set__(self,instance,value):
        print('in __set__')
        if not isinstance(value,self.type_):
            raise TypeError('expected an %s' % self.type_)
        instance.__dict__[self.name] = value  # 将self.name变为实例P的属性

    def __delete__(self,instance):
        print('in __delete__')
        del instance.__dict__[self.name]

class Person(object):
    name = Attr('name', str)
    age = Attr('age', int)
    height = Attr('height', float)

p = Person()
p.name = 'Bob'
print(p.name)
p.age = '17'
print(p.age)

==========================================================

>>> class A:
...     pass
... 
>>> a = A()
>>> # a.x = value
>>> a.__dict__['x'] = value
Traceback (most recent call last):
  File "<ipython-input-22-5e039675ed4e>", line 1, in <module>
    a.__dict__['x'] = value
NameError: name 'value' is not defined

>>> 
==================================================================
class Attr:
    def __init__(self,key,type_):
        self.key = key
        self.type_ = type_

    def __set__(self,instance,value):
        print('in __set__')
        if not isinstance(value,self.type_):
            raise TypeError('must be %s' % self.type_)
        instance.__dict__[self.key]= value

    def __get__(self,instance,cls):
        print('in __get__',instance,cls)
        return instance.__dict__[self.key]

    def __delete__(self,instance):
        print('in __del__',instance)
        del instance.__dict__[self.key]

class Person:
    name = Attr('name',str)
    age = Attr('age',int)

#a = A()
#a.x = 5
#a.y = 6
##del a.x
#print(a.x)
#print(a.y)
#A.x
p = Person()
p.name = 'richardo'
p.age = '32'

posted @ 2020-07-27 23:07  Richardo-M-Lu  阅读(96)  评论(0编辑  收藏  举报