1 使用__slots__
# 定义类
class Students(object):
pass
# 给实例绑定属性和方法
s = Students()
s.name = "lisi"
print(s.name) # lisi
def set_age(self, age):
self.age = age
from types import MethodType
s.set_age = MethodType(set_age, s)
s.set_age(25)
print(s.age) # 25
'''
注意:给一个实例绑定的方法,对另一个实例是不起作用的
为了给所有实例都绑定方法,可以给class绑定方法
'''
def set_sex(self, sex):
self.sex = sex
# 给class绑定方法
Students.set_sex = set_sex
s.set_sex('man')
print(s.sex)
# 定义另一个对象
s1 = Students()
s1.set_sex('woman')
print(s1.sex)
# 使用__slot__来限制给添加实例的属性
class Person(object):
__slots__ = ('name', 'age')
p = Person()
p.name = 'zhangsan'
p.age = 18
p.sex = 'man' # 出错
'''
注意:__slots__定义的属性仅对当前类实例起作用,对继承的子类是不起作用的
除非在子类中也定义__slots__,这样子类实例允许定义的属性就是自身的__slots__加上父类的__slots__
'''
2 使用@property
# 使用@property
''' @property 装饰器负责把一个方法变成属性调用 '''
# 创建类
''' 把一个getter方法变成属性,只需要加上@property就可以,
此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值
'''
class Student(object):
@property
def score(self):
return self._score
@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
# 创建实例
s = Student()
s.score = 60
print(s.score)
3 多重继承
一个类可以继承多个父类,这样,一个子类就可以同时获得多个父类的所有功能。
MixIn:
在设计类的继承关系时,通常,主线都是单一继承下来的,如果要混入额外的功能,通过多重继承就可以实现。这种设计通常称之为MixIn。
4 定制类
4.1 __str__
# __str__
# 定义class
class Student(object):
def __init__(self, name):
self.name = name
# 打印对象
print(Student('lisi')) # <__main__.Student object at 0x104037630>
class Student(object):
def __init__(self, name):
self.name = name
def __str__(self):
return 'student object (name: %s)' % self.name
print(Student('lisi')) # student object (name: lisi)
4.2 __iter__
如果一个类想被用于for循环,就必须实现一个__iter__()方法,该方法返回一个迭代对象。__next__()方法拿到循环的下一个值。
# __iter__
# 定义一个求斐波那契数列的类
class Fib(object):
def __init__(self):
self.a, self.b = 0, 1
def __iter__(self):
return self # 实例本身就是迭代对象,所以返回自己
def __next__(self):
self.a, self.b = self.b, self.a + self.b
if self.a > 100:
raise StopIteration()
return self.a
for n in Fib():
print(n)
# for循环结果
1 1 2 3 5 8 13 21 34 55 89
4.3 __getitem__
使用此方法可以像list那样按照下标取出元素。
# __getitem__
class Fib(object):
def __getitem__(self, n):
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
# 调用函数,获取结果
f=Fib()
print(f[1],f[2],f[3],f[4]) # 1 2 3 5
# 向函数传入切片
class Fib(object):
def __getitem__(self, n):
if isinstance(n, int): # n是索引
a, b = 1, 1
for x in range(n):
a, b = b, a + b
return a
if isinstance(n, slice): # n是切片
start = n.start
stop = n.stop
if start is None:
start = 0
a, b = 1, 1
L = []
for x in range(stop):
if x >= start:
L.append(a)
a, b = b, a + b
return L
# 调用函数,获取结果
f=Fib()
print(f[0:5]) # [1, 1, 2, 3, 5]
4.4 __getattr__
正常情况下,调用类的方法或属性时,如果不存在,就会报错,要避免这个错误,可以使用__getattr__()方法,动态返回一个属性。
# __getattr__
# 返回属性
class Student(object):
def __init__(self):
self.name = 'lisi'
def __getattr__(self, attr):
if attr=='score':
return 99
stu2=Student()
print(stu2.name) # lisi
print(stu2.score) # 99
# 返回函数
class Student(object):
def __getattr__(self, attr):
if attr=='age':
return lambda: 25
stu3=Student()
print(stu3.age()) # 25
4.5 __call__
直接调用实例本身
# __call__
class Student(object):
def __init__(self, name):
self.name = name
def __call__(self):
print('My name is %s.' % self.name)
stu4=Student('lisi')
stu4() # My name is lisi.