2020.04.29
限制动态添加属性
如果在类定义时,在类中添加了一个类级别的属性(也就是属性添加在与方法同级),并且这个属性命名有特殊的规定,只能为:slots
具体使用方法如下:
class s(object):
__slots__ = ('name','age')
//something else
此时如果在代码中想要给给类的实例添加不在__slots__中的属性/方法名,虽然在添加时不会报错,但是实际上并没有添加上,后续再访问的该动态添加的属性时就会报错:
has no attribute
但是,__slots__属性只对定义它的类有效,对于其子类无效。
但是很奇怪的是,在python中,如果子类和父类都定义了__slots__属性。那么子类中的__slots__是子类与父类__slots__的并集。
限制动态添加属性的值的范围
需要使用到装饰器decorator的@property标签,具体使用方法如下:
//假设想给一个类添加一个score属性,并且限制该属性在0-100范围内
class s(object):
#首先使用property标签标注在与想要添加的属性名相同的方法上,该方法相当于一个setter方法
@property
def score(self):
return self._score #注意这里一定要这样定义属性,带上前缀单下划线。不然会重复调用
#然后使用配套的setter标签,用法如下
@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") #限制值的范围
如果只定义了setter而没有定义getter标签(只有property没有.setter)。那么该属性只读。
如果一个类中定义的属性或者方法名开头和结尾都是有双下划线“__”,在python中这样的属性或方法是具备特殊作用的。
比如上面提到的__slots__属性,用于限制实例动态绑定的属性。
同样,在定义的每个类中的__init__函数(如果有。但是如果没有就继承父类的),这个函数相当于override构造函数。
接下来学习其他类似__init__函数:
①__str__函数
一般而言,str函数在python中用于将传入的参数转为字符串,并且如果直接输出一个实例的名字,实际上也会自动调用这个函数,此时如果定义的类中没有override str()函数(也就是没有定义__str__方法),此时一般会返回类名+地址。
而如果此时想要在调用实例名字的时候,输出我们想要其返回的信息如当前的属性信息等,就可以在该类中定义函数名为__str__的函数,重写str函数,如下:
class s(object):
def __str__(self):
#返回想要的信息
return some information
-此时再调用该类的实例名就会返回想要返回的信息。
tips:
在python中还有一个repr()函数,用法与str函数一样,主要用于调试。同样可以在类中重写该方法,重写的方法一样,不过也可以用一个小技巧:
在重写的__str__方法后,在与定义方法同级的位置使用:
repr = str
语句
②__iter__函数
从名字可以看出,这是迭代器方法。
也就是说,如果一个类实现了该方法,这个就可以被迭代,也就是可以用在for循环中(数字是不行的)。
根据java的使用经验,迭代器一般都有一个next()方法,python中同样,这两个方法配套使用。
具体使用如下:
//使用斐波那契数列函数
class fib(object):
def __init__(self):
self.a, self.b = 0 #定义初始值
def __iter__(self):
return self #返回迭代的本身
def __next__(self):
self.a,self.b = self.b,self.a+self.b #斐波那契计算公式
if self.a > 100000: #设置循环次数
raise StopIteration()
return self.a #返回下一个值
-此时就可以直接在for循环中使用该类:
for iter in fib():
print(iter)
-会打印一系列斐波那契数列直至循环条件再结束。
③__getitem__
该函数主要用于按下标取元素,就像列表、元组那样。
如果一个类重写该方法,该类中的元素就可以按下标取出。
依然以斐波那契为例:
#这里只写出该方法而不全部再写该类
def __getitem__(self, n):
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
④__getattr__函数
该函数主要用于对属性的查询。
对于没有重写该方法的类,如果其实例要查询一个不存在属性,此时就会报错。当重写该方法后,就可以进一步的动态添加查询的属性。使用如下:
class r(object):
def __init__(self,n):
self.name = n
def __getattr__(self,attr):
if attr == 'score':
return 111
raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)
上面的代码表示,现在该类的实例拥有一个必定存在的name属性,仅此而已。
此时定义的__getattr__函数体表示:
如果查询的属性是score属性,那么此时就动态的追加调用者实例score属性,并赋值111。
如果不是score则抛出异常。
这样使得程序健壮性更好。
⑤__call__函数
定义该函数的类,可以像调用函数那样调用自身,具体如下:
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
-
>>>s = Student("sss")
>>>s()
My name is sss.
-
可以看到,Student类的实例像调用函数那样调用自身:s()。
此时Student可以被称为一个callable对象,也就是可调用对象。
可以使用callable()函数查询:
>>>callable(Student)
true
>>>callable(str)
false
callable([])
false