[关闭]
@yanglt7 2018-12-03T07:45:42.000000Z 字数 3334 阅读 638

Python20_多重继承和定制类

Python


多重继承

  1. class Animal(object):
  2. pass
  3. class Mammal(Animal):
  4. pass
  5. class Bird(Animal):
  6. pass
  7. class Dog(Mammal):
  8. pass
  9. class Bat(Mammal):
  10. pass
  11. class Parrot(Bird):
  12. pass
  13. class Ostrich(Bird):
  14. pass
  15. class Runnable(object):
  16. def run(self):
  17. print('Running...')
  18. class Flyable(object):
  19. def fly(self):
  20. print('Flying...')
  21. class Dog(Mammal,Runnable):
  22. pass
  23. class Bat(Mammal,Flyable):
  24. pass

通过多重继承,一个子类就可以同时获得多个父类的所有功能。

MixIn

MixIn 的目的就是给一个类增加多个功能,这样,在设计类的时候,我们优先考虑通过多重继承来组合多个 MixIn 的功能,而不是设计多层次的复杂的继承关系

  1. class Dog(Mammal, RunnableMixIn, CarnivorousMixIn):
  2. pass

定制类

__str__

  1. >>> class Student(object):
  2. ... def __init__(self, name):
  3. ... self.name = name
  4. ...
  5. >>> print(Student('Michael'))
  6. <__main__.Student object at 0x109afb190>
  1. >>> class Student(object):
  2. ... def __init__(self,name):
  3. ... self.name=name
  4. ... def __str__(self):
  5. ... return 'Student object (name:%s)' % self.name
  6. ...
  7. >>> print(Student('Michael'))
  8. Student object (name:Michael)
  9. >>> s = Student('Michael')
  10. >>> s
  11. <__main__.Student object at 0x109afb310>
  1. class Student(object):
  2. def __init__(self, name):
  3. self.name = name
  4. def __str__(self):
  5. return 'Student object (name=%s)' % self.name
  6. __repr__ = __str__
  7. >>> s=Student('Michael')
  8. >>> s
  9. Student object (name=Michael)

__iter__

如果一个类想被用于 for ... in 循环,类似 list 或 tuple 那样,就必须实现一个 __iter__() 方法,该方法返回一个迭代对象,然后,Python 的 for 循环就会不断调用该迭代对象的 __next__() 方法拿到循环的下一个值,直到遇到 StopIteration 错误时退出循环。

  1. >>> class Fib(object):
  2. ... def __init__(self):
  3. ... self.a,self.b=0,1
  4. ... def __iter__(self):
  5. ... return self
  6. ... def __next__(self):
  7. ... self.a,self.b=self.b,self.a+self.b
  8. ... if self.a>1000:
  9. ... raise StopIteration()
  10. ... return self.a
  11. ...
  1. >>> for n in Fib():
  2. ... print(n)
  3. ...
  4. 1
  5. 1
  6. 2
  7. 3
  8. 5
  9. 8
  10. 13
  11. 21
  12. 34
  13. 55
  14. 89
  15. 144
  16. 233
  17. 377
  18. 610
  19. 987

__getitem__

Fib 实例虽然能作用于 for 循环,看起来和 list 有点像,但是,把它当成 list 来使用还是不行,要表现得像 list 那样按照下标取出元素,需要实现 __getitem__() 方法:

  1. >>> class Fib(object):
  2. ... def __getitem__(self,n):
  3. ... a,b=1,1
  4. ... for x in range(n):
  5. ... a,b=b,a+b
  6. ... return a
  7. ...
  8. >>> f=Fib()
  9. >>> f[0]
  10. 1

__getitem__() 传入的参数可能是一个 int,也可能是一个切片对象 slice,要做判断才能切片:

  1. >>> class Fib(object):
  2. ... def __getitem__(self,n):
  3. ... if isinstance(n,int):
  4. ... a,b=1,1
  5. ... for x in range(n):
  6. ... a,b=b,a+b
  7. ... return a
  8. ... if isinstance(n,slice):
  9. ... start=n.start
  10. ... stop=n.stop
  11. ... if start is None:
  12. ... start=0
  13. ... a,b=1,1
  14. ... L=[]
  15. ... for x in range(stop):
  16. ... if x>=start:
  17. ... L.append(a)
  18. ... a,b=b,a+b
  19. ... return L
  20. ...
  21. >>> f=Fib()
  22. >>> f[0:5]
  23. [1, 1, 2, 3, 5]

但是没有对 step 参数作处理:

  1. >>> f[:10:2]
  2. [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]

也没有对负数作处理,所以,要正确实现一个 __getitem__() 还是有很多工作要做的。

此外,如果把对象看成 dict,__getitem__() 的参数也可能是一个可以作 key 的 object,例如 str。

与之对应的是 __setitem__() 方法,把对象视作 list 或 dict 来对集合赋值。最后,还有一个 __delitem__() 方法,用于删除某个元素。

__getattr__

写一个 __getattr__() 方法,动态返回一个属性。

  1. >>> class Student(object):
  2. ... def __init__(self):
  3. ... self.name='Michael'
  4. ... def __getattr__(self,attr):
  5. ... if attr=='score':
  6. ... return 99
  7. ...
  8. >>> s=Student()
  9. >>> s.name
  10. 'Michael'
  11. >>> s.score
  12. 99

返回函数也是完全可以的:

  1. >>> class Student(object):
  2. ... def __getattr__(self,attr):
  3. ... if attr=='age':
  4. ... return lambda:25
  5. ...
  6. >>> s=Student()
  7. >>> s.age()
  8. 25

此外,注意到任意调用如 s.abc 都会返回 None,这是因为我们定义的 __getattr__ 默认返回就是 None。要让 class 只响应特定的几个属性,我们就要按照约定,抛出 AttributeError 的错误:

  1. class Student(object):
  2. def __getattr__(self,attr):
  3. if attr=='age':
  4. return lambda:25
  5. raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)

__call__

任何类,只需要定义一个 __call__() 方法,就可以直接对实例进行调用。请看示例:

  1. >>> class Student(object):
  2. ... def __init__(self,name):
  3. ... self.name=name
  4. ... def __call__(self):
  5. ... print('My name is %s.' % self.name)
  6. ...
  7. >>> s=Student('Michael')
  8. >>> s()
  9. My name is Michael.

__call__()还可以定义参数。能被调用的对象就是一个Callable对象

  1. >>> callable(max)
  2. True
  3. >>> callable([1,2,3])
  4. False
  5. >>> callable(None)
  6. False
  7. >>> callable('str')
  8. False
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注