一、深入类和对象
鸭子类型和多态
多态的概念是应用于Java和C#这一类强类型语言中,而Python崇尚"鸭子类型"
1.1 鸭子类型
a = [1,2]
b = [3,4]
c = (5,6) # 元组 tuple
d = {7,8} # 集合 set 无序的
# def extend(self,iterable): iterable可迭代的对象 可以用for
a.extend(d)
print(a)
结果: [1, 2, 8, 7]
其中,def extend(self,iterable): iterable可迭代的对象 可以用for
动态语言调用实例方法时不检查类型,只要方法存在,参数正确,就可以调用。这就是动态语言的“鸭子类型”,它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走起路来像鸭子”,那它就可以被看做是鸭子。
1.2 多态
所谓多态:定义时的类型和运行时的类型不一样,此时就成为多态。
class Cat(object):
def say(self):
print("i am Cat")
class Dog(object):
def say(self):
print("i am Dog")
class Duck(object):
def say(self):
print("i am Duck")
animal_list = [Cat, Dog, Duck]
for animal in animal_list:
animal().say()
结果: i am Cat
i am Dog
i am Duck
二、抽象基类(abc模块)
应用场景1、判断某个对象的类型
class Demo(object):
def __init__(self, names):
self.names = names
def __len__(self):
return len(self.names)
def test(self):
pass
d = Demo(['je','qw'])
print(len(d))
# hasattr判断是否有这个方法
print(hasattr(d, 'test')) # True
from collections.abc import Sized
print(isinstance(1, int)) # True
print(isinstance(d, Sized)) # True 检查d有没有__len__方法,因为Sized里面有__len__方法
Sized方法里面有__subclasshook__来实现判断 有没有__len__方法
应用场景2、需要强制某个子类必须实现某些方法
'''
我们需要强制某个子类必须实现某些方法
如果自己写web框架 要集成cache redis memcache等缓存
@abc.abstractmethod -- 装饰器
metaclass=abc.ABCMeta 是 抽象基类,子类必须重写类方法
有@abc.abstractmethod,如果 重写,则会报错
'''
import abc
class CacheBase(metaclass=abc.ABCMeta):
@abc.abstractmethod
def get(self, name):
# raise ValueError
pass
@abc.abstractmethod
def set(self, key,value):
# raise NotADirectoryError
pass
class RedisBase(CacheBase):
# 重写父类中的方法
def get(self, key):
pass
def set(self, key, value):
pass
r = RedisBase()
# r.get('wee')
# print(r)
结论:
- metaclass=abc.ABCMeta 是 抽象基类,子类必须重写类方法
- 有@abc.abstractmethod,如果 重写,则会报错
三、isinstance 和 type的区别
if isinstance(i, int):
print(1234) # 可以打印
if type(i) is "int":
print('qweqw') # 打印不出来
class A:
pass
class B(A):
pass
b = B()
print(isinstance(b, B))
print(isinstance(b, A)) # True 考虑类的继承关系
print(type(b) is B)
print(type(b) is A) # False 没有考虑类的继承关系
# == value
# 和 is 内存地址
四、类变量和对象变量
class A:
# 类属性 类方法
aa = 1
# 实例方法
def __init__(self, x, y):
# x ,y 实例属性
self.x = x
self.y = y
a = A(1, 2)
print(a.x, a.y, a.aa) # 1 2 1 可以向下查找
# print(A.x) # 报错,不可向下查找
A.aa = 11 # 重新赋值
a.aa = 22
print(a.aa) # 22
print(A.aa) # 11
b = A(1, 2)
print(b.aa) # 11 b.aa相当于A.aa
类属性和实例属性以及查找顺序
MRO算法
Python2.2之前的算法:金典类
DFS(deep first search):A->B->D->C->E
class D:
pass
class B(D):
pass
class E:
pass
class C(E):
pass
class A(B, C):
pass
print(A.__mro__)
# 顺序
# (<class '__main__.A'>, <class '__main__.B'>,
# <class '__main__.D'>, <class '__main__.C'>,
# <class '__main__.E'>, <class 'object'>)
Python2.2版本之后,引入了BFS(广度优先搜索)
BFS:A->B->C->D
class D:
pass
class B(D):
pass
class C(D):
pass
class A(B, C):
pass
print(A.__mro__)
# (<class '__main__.A'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class 'object'>)
在Python2.3之后,Python采用了C3算法
Python新式类继承的C3算法:https://www.cnblogs.com/blackmatrix/p/5644023.html
五、Python对象的自省机制
自省是通过一定的机制查询到对象的内部结构
Python中比较常见的自省(introspection)机制(函数用法)有: dir(),type(), hasattr(), isinstance(),通过这些函数,我们能够在程序运行时得知对象的类型,判断对象是否存在某个属性,访问对象的属性。
六、super函数
在类的继承中,如果重定义某个方法,该方法会覆盖父类的同名方法,但有时,我们希望能同时实现父类的功能,这时,我们就需要调用父类的方法了,可通过使用 super 来实现
class A:
def __init__(self):
print('A')
class B(A):
def __init__(self):
print('B')
# python2的写法
super(B, self).__init__()
# python3的写法
super().__init__()
b = B()
6.1 重写了B的构造函数 为什么还要去调用super
class People(object):
def __init__(self, name, age, weight):
self.name = name
self.age = age
self.weight = weight
def speak(self):
print("%s 说:我%d岁了"%(self.name, self.age))
class Student(People):
def __init__(self,name, age, weight, grade):
# self.name = name
# self.age = age
# self.weight = weight
# super().__init__(name ,age, weight)
People.__init__(self, name, age, weight)
self.grade = grade
def speak(self):
print("%s 说:我%d岁了 我在读%d年级"%(self.name, self.age, self.grade))
s = Student('YYY', 20, 50, 6)
s.speak()
结果: YYY 说:我20岁了 我在读6年级
super 执行顺序到底是什么样的?
class A:
def __init__(self):
print("A")
class B(A):
def __init__(self):
print("B")
super().__init__()
class C(A):
def __init__(self):
print("C")
super().__init__()
class E:
pass
class D(B, C):
def __init__(self):
print("D")
super().__init__()
d = D()
print(D.__mro__) # D B C A E