实现继承:
>>> class Animal(object):
... pass
...
>>> class Mammal(Animal):
... pass
...
>>> class Bird(Animal):
... pass
...
>>> class Dog(Mammal):
... pass
...
>>> class Bat(Mammal):
... pass
...
>>> class Parrot(Bird):
... pass
...
>>> class Ostrich(Bird):
... pass
...
定义Runnable 和 Flyable 两个类:
>>> class Runnable(object):
... def run(self):
... print('Running...')
...
>>> class Flyable(object):
... def fly(self):
... print('Flying...')
...
多继承:
>>> class Dog(Mammal, Runnable): #dog多继承一个Runnable
... pass
...
>>> class Bat(Mammal, Flyable): #Bat 多继承一个Flyable
... pass
...
通过多继承,一个子类就可以获取多个父类的所有功能
打印实例信息:
>>> class Student(object):
... def __init__(self, name):
... self.name = name
...
>>> print(Student('Michael'))
<__main__.Student object at 0x000001F96FC06898>
可以看到打印的内容不好看
定义 str()方法,返回好看的字符串:
>>> class Student(object):
... def __init__(self, name):
... self.name = name
... def __str__(self):
... return 'Student object (name: %s)' % self.name
...
>>> print(Student('Michael'))
Student object (name: Michael)
如果不用 print,打印的效果:
>>> s = Student('Michael')
>>> s
<__main__.Student object at 0x000001F96FC06978>
这是因为 直接显示变量没有调用__str__(), 而是__repr__()。那么为了显示好看点,那么可以进行 重写,当然为了简便,我们直接赋值。
简便的重定义__repr__():
>>> class Student(object):
... def __init__(self, name):
... self.name = name
... def __str__(self):
... return 'Student object (name = %s)' % self.name
... __repr__ = __str__
...
>>> s = Student('Michael')
>>> s
Student object (name = Michael)
通过 iter() 方法返回一个迭代对象, Python 的 for循环不断调用迭代对象的 next()方法, 实现斐波那契数列:
>>> class Fib(object):
... def __init__(self):
... self.a, self.b = 0, 1 #初始化两个计数器 a, b
... 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 n in Fib():
... print(n)
...
1
1
2
3
5
...
46368
75025
通过 getitem 获取 Fib 对应下标元素:
>>> 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()
>>> f[0]
1
>>> f[100]
573147844013817084101
list 切片方法:
>>> list(range(100))[5:10]
[5, 6, 7, 8, 9]
对 Fib 进行切片:
>>> f = Fib()
>>> f[0:5]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 4, in __getitem__
TypeError: 'slice' object cannot be interpreted as an integer
发现对 Fib 作切片出错了。原因是 getitem()传入的参数可能是一个 int,也可能是对象的 slice 所以要作判断
正确的 Fib 切片:
>>> class Fib(object):
... def __getitem__(self, n):
... if isinstance(n, int):
... a, b =1, 1
... for x in range(n):
... a, b = b, a + b
... return a
... if isinstance(n, slice):
... 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()
>>> f[0:5]
[1, 1, 2, 3, 5]
>>> f[:10]
[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]
>>>
获取不存在的属性会报错:
>>> class Student(object):
... def __init__(self):
... self.name = 'Michael'
...
>>> s = Student()
>>> s.name
'Michael'
>>> s.score
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Student' object has no attribute 'score'
通过使用 getattr 方法,可以避免报错:
>>> class Student(object):
... def __init__(self):
... self.name ='Michael'
... def __getattr__(self, attr):
... if attr == 'score':
... return 99
...
>>> s = Student()
>>> s.name
'Michael'
>>> s.sco # 获取不存在的属性,会默认返回None
>>> s.score # 获取不存在的属性,会试图调用 __getattr__(self, 'score') 来获取 score 值
99
也可以返回函数:
>>> class Student(object):
... def __getattr__(self, attr):
... if attr == 'age':
... return lambda: 25
...
>>> s = Student()
>>> s.age()
25
注意,只有在没有找到对应的属性,才会调用__getattr__() 方法。
只响应特定的属性,其他的就提示报错:
>>> class Student(object):
... def __getattr__(self, attr):
... if attr == 'age':
... return lambda:25
... raise AttributeError('\'Student\' object has no attribute \'%s\'' % attr)
...
>>> s = Student()
>>> s.a
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 5, in __getattr__
AttributeError: 'Student' object has no attribute 'a'
>>> s.age()
25
灵活应对API 改动,利用__getattr__,我们写一个链式调用:
>>> class Chain(object):
... def __init__(self, path=''):
... self._path = path
... def __getattr__(self, path):
... return Chain('%s/%s' %(self._path, path))
... def __str__(self):
... return self._path
... __repr__ = __str__
...
>>> Chain().status.user.timeline.list
/status/user/timeline/list
一般通过实例再调用方法 如:instance.method()。 但通过 call() 可以实现对实例本身上的调用:
>>> class Student(object):
... def __init__(self, name):
... self.name = name
... def __call__(self):
... print('My name is %s.' % self.name)
...
>>> s = Student('Michael')
>>> s()
My name is Michael.
通过callable() 判断一个对象是否能直接被调用:
>>> callable(Student('ssz')) # Student 带有 __call__
True
>>> callable(max) # max 是一个 Callable对象
True
>>> callable(None)
False
>>> callable('str')
False
总结: 1、一个子类通过多继承来实现父类的所有功能 2、定义__str__ 方法让打印的字符串更好看 3、重新定义__repr__() 让直接显示变量的字符串更好看 4、iter 来实现返回迭代对象 5、getattr 使获取不存在的属性不报错 6、callable()判断一个对象是否可以直接被调用