描述符应用 -- 让python变成一个强类型的语言

众所周知,python是一门弱类型的语言,变量可以随意赋值成任意类型,但是通过描述符,我们可以把数据变成强类型的。

我们为数据设置数据描述符,因为数据描述的优先级大于实例属性,所以在给数据赋值的时候会优先出发数据描述符。

 

普通版

class Typed:
    def __init__(self, name, expected_type):
        self.name = name
        self.expected_type = expected_type

    def __get__(self, instance, owner):
        if instance is None:
            return self  # 如果实例化用People.name调用的话,就返回Typed的实例name
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        if not isinstance(value, self.expected_type):
            raise TypeError('Type error')
        instance.__dict__[self.name] = value

    def __delete__(self, instance):
        instance.__dict__.pop(self.name)


class People:
    name = Typed('name', str)
    age = Typed('age', int)
    salary = Typed('salary', float)

    def __init__(self, name, age, salary):
        self.name = name
        self.age = age
        self.salary = salary


# p1 = People(123, 18, 3333.3)  # TypeError: Type error
# p1=People('egon','18',3333.3) # TypeError: Type error
# p1=People('egon',18,3333)  # TypeError: Type error

p1 = People('egon', 18, 3333.33)  # 正确

 

用类的装饰器实现

先回顾一下setattr的语法

语法

setattr() 语法:

setattr(object, name, value)

参数

  • object -- 对象。
  • name -- 字符串,对象属性。
  • value -- 属性值。
class Typed:
    def __init__(self, name, expected_type):
        self.name = name
        self.expected_type = expected_type

    def __get__(self, instance, owner):
        if instance is None:
            return self
        return instance.__dict__[self.name]

    def __set__(self, instance, value):
        if not isinstance(value, self.expected_type):
            raise TypeError('type error')
        instance.__dict__[self.name] = value

    def __delete__(self, instance):
        self.__dict__.pop(self.name)


def typeassert(**kwargs):
    def decorator(cls):
        for name, expected_type in kwargs.items():
            setattr(cls, name, Typed(name, expected_type))
        return cls

    return decorator


@typeassert(name=str, age=int, salary=float)
class People:
    def __init__(self, name, age, salary):
        self.name = name
        self.age = age
        self.salary = salary


p1 = People('edward', 18, 30000.00)

 

posted @ 2019-02-21 22:23  梁少华  阅读(660)  评论(0编辑  收藏  举报