在设计类的时候可以根据自己的需要定制类,其中主要用到的有__slots__、__str__、__repr__、__len__、__iter__、__next__、__getitem__、__setitem__、__getattr__、__call__等特殊的函数名以及@property和@xxx.setter。每个都有其特殊意义,能有助于我们更好的设计类控制类。
__slots__:
用于限制属性的关键词,如图当设计了S类只有‘name’和‘age’时,用动态创建对象属性就会报AttributeError错误。这样可以防止外部尚自增加属性。
__str__与__repr__:
这个有点像Java里面的toString函数,当我们打印这个对象时会自动调用这个函数。如图:
在打印对象时,会调用默认的__str__函数,当自行定义__str__函数之后,默认的函数就被隐藏了。而__repr__其实就是当直接用对象时(不用print),默认调用__repr__,但是系统默认时没有,这里就简接调用了__str__。
__len__:
用于重写长度返回,对应len()函数,当设计一些特殊的类时无法长度没法直接用len()来测量,就用__len__来自行定义len()。
如图,这样再复杂的类,都可以定于出需要的len()。(特别注意:图中的num是类属性,b.num只是创建了一个新的对象属性,不明白可以看上一篇“类属性与对象属性”:https://blog.youkuaiyun.com/shungry/article/details/90083026)
__iter__与__next__:
主要用于设计相应的迭代类,可以用for寻址直接进行迭代,如图:
__iter__ 用于返回迭代器,用for语句进行调用迭代器的next()函数,图中是直接返回了自己作为迭代器,并为自己设计了一个next()函数(即__next__),从莫种意义上说,这就是一个Iterator,如图:
__getitem__与__setitem__:
可以用来像list,tuple,dict一样用“[]”进行访问内部的数据元素,继续对上面的例子进行改进,如图:
__getattr__:
与getitem类似,这是对属性进行设置和读取,可以用于对没定义的属性进行控制。当调用的属性是存在时,会去直接调用其属性(跳过getattr),只有在没有其属性时才会调用,如图:
调用已有属性时会跳过getattr,如果没有属性且不匹配默认返回None。
__call__:
可以用来把自己类当函数使用,这里就模糊了类与函数的界限,感觉更加的灵活了。可以设想一下事件是一个类,但又可以直接以函数的方式调用事件类用以完成一些特定的事项,以下是简单的抽象例子:
@property和@xxx.setter:
对类里面的属性进行简单的赋值是允许的(如:a.name = 'f'),但这并没有对赋值的数据进行验证和检查,导致可靠性不高。
@property用在你要设置验证的属性前,在获取该属性时进行返回,也可加入其他代码。
@xxx.setter会更具@property修饰的属性而产生,主要用于设置属性时的,条件添加。
如图,当访问时添加了一句“you want to get data:”,在赋值时进行了字符串的验证或错误的抛出。
值得注意的是:其本质其实是通过装饰器进行的装饰,具体后讲。