CSIC_716_20191128【多态、绑定与非绑定方法、isinstance与issubclass 】
多态
what: 同一个事物有不同的形态。
多态的目的:在不知道对象具体类型的情况下,统一对象调用方法的规范。(通俗讲,即规定实现同样功能的方法,一定要起同样的名字)。
多态的表现形式之一就是继承,先抽象再继承。
多态的父类:定制一套统一的规范,子类中重写该方法,并使用这个方法名。
python中不会强制限制子类一定要用父类规定的方法名,所以出现了抽象类。
抽象类
what:python中内置了abc模块中有抽象类 import abc
抽象类的作用:让子类必须遵循父类的编写规范。
抽象类不可以被实例化
如何实现抽象类:请看代码
# _*_ coding: gbk _*_ # @Author: Wonder import abc class Father(metaclass=abc.ABCMeta): # 定义时候要加上metaclass = abc.ABCMeta @abc.abstractmethod # 被@abc.abstractmethod装饰的方法,必须在子类中重写,否则会报错。 def bark(self): print('barking......') @abc.abstractmethod def run(self): print('running......') def dance(self): print('dancing......') class Sub(Father): def poke(self): print('poking......') def bark(self): # 重写父类方法,不写会报错 print('sub barking......') def run(self): print('sub running......') test = Sub() test.run() test.bark() test.dance() test.poke()
注意点:1.父类名后要加上 classmeta = abc.ABCMeta 2.父类方法上要加上@abc.abstractmethod 3.子类务必遵循父类方法的编写规范进行重写,缺一不可。
鸭子类型
鸭子类型是多态的一种表现形式。
针对不同的对象,根据特点先抽象出相同的方法,再制定一套统一的编写规范
在定义类时,类中的方法都按照统一的规范进行编写。
鸭子类型取消了继承,也取消了抽象类,全凭自觉按照规范编写。这样耦合度就很低。
鸭子类型可以封装出若干个统一的对外的接口,调用相似事物的相同方法,例如:
# _*_ coding: gbk _*_ # @Author: Wonder class Dog: def bark(self): print('dog barking') class Cat: def bark(self): print('cat barking') class Bird: def bark(self): print('bird barking') def BARK(animal): # 封装统一对外接口 animal.bark() dog = Dog() cat = Cat() bird = Bird() BARK(dog) BARK(cat) BARK(bird)
总结:
多态的三种表现形式:
>>>继承父类 中度耦合(父类给了规范,但子类可以自由发挥,不用父类的规范)
>>>继承抽象类 高耦合(父类给了规范,并严格限制子类按照规范重写override)
>>>鸭子类型 低耦合(没有继承,类中的方法名 全凭自觉 按照规范编写)
绑定方法classmethod和非绑定方法staticmethod
classmethod和staticmethod都是pyhton内置的装饰器
classmethod用来标识 类中的某个方法是类的绑定方法。由类来调用,自动传入方法的第一个参数是类。
之前学过类中不加修饰的方法是对象的绑定方法,对象调用这些方法时,会将自身作为第一个参数传入方法,当成self。
(这一条不知道能否这么总结) 如果对象调用类的绑定方法,第一个传入的值是对象所在的类,子类生成的对象可以调用父类和子类的绑定方法。
# _*_ coding: gbk _*_ # @Author: Wonder ''' classmethod: 类的绑定方法,只有类可以使用,子类也可以使用。 ''' class Father: __key = 'secret' def __init__(self, name): self.name = name @classmethod def call(cls, x, y, z): return x + y, y + z @classmethod def info(cls, key): if key == 'wonder': return cls.__key, cls return 'FUCK_NO' class Sub(Father): __key = 1990 pass sub_obj = Sub('name') # 子类实例化一个对象 print(sub_obj.__class__) #查看对象所属的类为 <class '__main__.Sub'> res = sub_obj.info('wonder') print(res) # ('secret', <class '__main__.Sub'>) 此处需要注意,cls.__key一定找当前类中的,不可以跨类。 print(Father.call(1, 2, 3)) # (3, 5) print(Sub.call(4, 5, 6)) # (9, 11) print(Father.info('won')) # FUCK_NO print(Sub.info('wonder')) # ('secret', <class '__main__.Sub'>)
非绑定方法
非绑定方法,相当于在类中定义了一个函数,没有自动传参功能,类和对象都可以使用。
# _*_ coding: gbk _*_ # @Author: Wonder class Foo: @staticmethod def rap(name): print(f'您的狗名为{name}') foo_obj = Foo() foo_obj.rap('阿黄') Foo.rap('阿黑')
isinstance 判断一个对象是否是一个类的实例
issubclass 判断一个类是否是另一个类的子类
class A: pass class B(A): pass class C: pass print(isinstance(A(), A)) # True print(isinstance(B(), A)) # True print(isinstance(A(), B)) # False print(isinstance(B(), B)) # True print(issubclass(C, A)) # False print(issubclass(B, A)) # True
补充
uuid模块
import uuid print(uuid.uuid4()) # a64b11d5-a3f1-46a2-b752-08fc8949457a
uuid.uuid4( ) uuid4是一个纯随机数,与机器无关, 相重的几率很小。通常生成用户id用这个。