鸭子类型与多态
鸭子类型
对于像Java和C#的强类语言多应用与多态的概念,而python却属于鸭子类型。
鸭子类型指的就是在调用实例化方法时,不检查类型,只要你方法存在,参数正确,就可以运行该方法。属于动态语言;它并不要求严格的继承体系,一个对象只要“看起来像鸭子,走路也想鸭子。”那么这就可以看成是鸭子类型。
多态
指的是定义的和运行的类型不一样,那么就可以被成为多态。
如下面的代码所示,只要这个extend的方法存在,参数正确,它并不分析类型是否正确,在最底层都会处理,然后正确输出结果。
a = [1,2]
b = [2,3]
c = (3,4)
d = "abc"
# a.extend(b)
# a.extend(c)
a.extend(d)
print(a)
多态的一个简单例子,指在运行的跟定义的不一致
class Cat(object):
def info(self):
print("i ilke fish")
class Dog(object):
def info(self):
print("i like meat")
class pig(object):
def info(self):
print("i like sleep")
# 将三个类放在同一个列表中
animal_list = [Cat,Dog,pig]
for animal in animal_list: # 遍历时要先实例化对象,才可调用。
animal().info()
'''
鸭子类型 指在运行之前, Cat Dog都是在列表中,被当成变量
当运行的时候, 加上()实例化,调用info()才明确这三个是一个类
'''
抽象基类
抽象基类就是在类里定义了纯虚化成员函数的类。纯虚函数只提供接口,并没有实现;指定义各种方法而不做具体实现的类,任何继承自抽象基类的 类必须实现这些方法,否则无法实现实例化。
可以说抽象基类不能被实例化,通常是作为基类供子类继承,子类中重写虚函数,实现具体的接口。
判断类方法中的魔法方法,内置方法;
'''
abc模块
'''
class Demo(object):
def __init__(self,x):
self.x = x
def __len__(self):
return len(self.x)
# 实例化
l = ['a','b','c']
d = Demo(l)
# print(d) # 显示的是内存地址 <__main__.Demo object at 0x00000210219D1C48>
# print(len(d)) # 3; 触发len方法
# 判断类中内部是否含有某种魔法方法 使用hasattr()
# print(hasattr(d,"__len__")) # True 返回布尔值
# 导入abc模块
from collections.abc import Sized
# 判断d 是否是 Sized 这个类
print(isinstance(d,Sized)) # 返回True
'''
通过判断d 是否是 Sized的子类 然后进一步判断d这个对象的类,是否含有__len__
'''
实现子类重写父类
子类若是不重写父类中的方法,就直接报错:
class Father(object):
def dele(self):
raise NotImplementedError
def crea(self):
raise NotImplementedError
class Son(Father):
def dele(self):
print("aaa")
# r = Son()
# r.crea()
# r.dele() # 可以访问到父类的方法
'''
1. 子类 如果不重写父类的方法 访问时 直接抛出异常 父类方法中直接引入错误 raise
'''
r = Son()
r.dele()
使用抽象基类的方法来调出异常:
抽象基类:在实例化的时候检测
主动抛出异常: 调用时才会检测
在实际工作中,使用这种方法较好!
import abc
# 使用抽象基类的方法来定义父类 不是继承object 而是继承abc.ABCMeta
class Father(metaclass=abc.ABCMeta):
@abc.abstractmethod # 装饰器 变成抽象基类的方法
def dele(self):
pass
@abc.abstractmethod
def crea(self):
pass
class Son(Father):
def dele(self):
print("aaa")
# 加上装饰器 后 不重写才会报错
r = Son()
r.crea()