python中的抽象类、接口类、元类、动态类、新式类、旧式类

元类有什么用

元类可以动态地创建类,它是制造类的工厂

类(class)实例化 一个 instance对象

type 的实例化就是 类class对象

type 是 Python 自建的元类

type () 函数能返回一个对象的类型 (类型本身也是对象),也就是返回对象的__class__属性值。

如何创建 class 对象呢?

最简单的办法

ini 复制代码
class MyClass: #python3默认是创建新式类,隐式继承了object
    a = 1

type函数

go 复制代码
type(name, bases, namespace)

MyClass = type('MyClass', (object,), dict(a=1))

-   name 对应于类的`__name__`属性
-   bases 对应于类的`__bases__`属性
-   namespace 对应于类的`__dict__`属性

动态类

type() 函数可以动态创建类,即在运行期动态创建类

如何控制类的创建行为?

使用 metaclass

比如我们想让自定义的类所创建的的对象自动包含 add 方法,即使类本身没有定义这个方法

python 复制代码
# metaclass是类的模板,所以必须从`type`类型派生:
class ListMetaclass(type):
    # __new__ 是在__init__之前被调用的特殊方法
    # __new__是用来创建对象并返回这个对象
    # 而__init__只是将传入的参数初始化给对象
    # 实际中,你很少会用到__new__,除非你希望能够控制对象的创建
    # 在这里,类是我们要创建的对象,我们希望能够自定义它,所以我们改写了__new__
    # 如果你希望的话,你也可以在__init__中做些事情
    # 还有一些高级的用法会涉及到改写__call__,但这里我们就先不这样.
    def __new__(cls, name, bases, attrs):
        # cls:当前创建的类对象
        # name:类的名字
        # bases:类继承的父类集合
        # attrs:类的方法集合。
        print('name: ', name) # 这些打印会在创建MyList类对象的时候打印,而非在创建MyList实例对象的时候
        print('bases: ',bases)
        print('attrs: ', attrs)
        attrs['add'] = lambda self, value: self.append(value)
        return type.__new__(cls, name, bases, attrs)

class MyList(list, metaclass=ListMetaclass):
    pass

输出

python 复制代码
name:  MyList
bases:  (<class 'list'>,)
attrs:  {'__module__': '__main__', '__qualname__': 'MyList'}
>>> l=MyList() # 在创建MyList类的时候自动获得了add属性,即一个函数对象
>>> l.add('test1')
>>> l.add('test2')
>>> l
['test1', 'test2']

接口类

一种规范 规定子类应该具备的功能

定义了一些接口(就是函数,但这些函数都没有具体的实现),必须由引用类继承接口类

  • 接口的设计目的是 "协作" 与 "解耦合"
  • 接口类中没有实现所有的方法
  • 鸭子类型算是一种接口类的实现风格
ruby 复制代码
class Payment: # 接口类
    def pay(self, money):
        raise NotImplementedError

class AliPay(Payment): # 引用类具体实现
    def pay(self, money):
        print('AliPay')

class AppPay(Payment):
    def pay(self, money):
        print('AppPay')

class WeichatPay(Payment):
    def zhifu(self, money):
        print('WeichatPay')

def pay(payment, money):
    # 如果实现类没有提供pay方法,在运行的过程就会报异常,
    # 这也是我们接下来要介绍的抽象类存在的目的
    payment.pay(money)
    
>>> p = WeichatPay()
>>> pay(p, 40) # 抛出NotImplementedError

抽象类

一种规范 规定子类应该具备的功能

该类不能被实例化,只能被继承,且子类必须实现抽象方法

  • 抽象类的设计目的更多的是 "复用"
  • 抽象类实现部分方法
  • abc 模块就是用来实现抽象类的
  • 抽象基类的目的就是让别的类继承它以及实现特定的抽象方法
  • 可以去使用抽象基类做类型检查,这样就确保了子类实现了某些特定的方法

实现抽象基类的方法就是通过使用 abc 这个内建模块

python 复制代码
import abc

class Payment(abc.ABC):    # 使用抽象基类实现接口类
    # Payment是一个抽象基类,因为它继承了abc.ABC。
    # 另外,你也可以让它从元类ABCMeta直接创建

    # abc.abstractmethod这个装饰器去标记抽象方法
    # 实现细节由子类去完成
    @abc.abstractmethod
    def pay(self):
        pass

class AliPay(Payment): # 引用类具体实现
    def pay(self, money):
        print('AliPay')

class AppPay(Payment):
    def pay(self, money):
        print('AppPay')

class WeichatPay(Payment):
    def zhifu(self, money):
        print('WeichatPay')
        
>>> p = AliPay()
>>> isinstance(p, Payment)
True
>>> wp = WeichatPay() # 这里就直接报错了
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Cant instantiate abstract class WeichatPay with abstract methods

新式类和旧式类

Python 2.x 中默认都是经典类,只有显式继承了 object 才是新式类。

Python 3.x 中默认都是新式类,不必显式的继承 object

新式类对象可以直接通过__class__属性获取自身类型

新式类增加了__slots__内置属性,可以把实例属性的种类锁定到__slots__规定的范围之中

新式类采用广度优先搜索(bfs),而旧式类是采用深度优先搜索(dfs)

新式类增加了__getattribute__方法

继承搜索的顺序发生了改变

经典类多继承属性搜索顺序:

先深入继承树左侧,再返回,开始找右侧; 深度优先搜索(dfs)

新式类多继承属性搜索顺序

先水平搜索,然后再向上移动 广度优先搜索(bfs)

相关推荐
monkey_meng15 分钟前
【遵守孤儿规则的External trait pattern】
开发语言·后端·rust
Estar.Lee30 分钟前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
新知图书1 小时前
Rust编程与项目实战-模块std::thread(之一)
开发语言·后端·rust
盛夏绽放2 小时前
Node.js 和 Socket.IO 实现实时通信
前端·后端·websocket·node.js
Ares-Wang2 小时前
Asp.net Core Hosted Service(托管服务) Timer (定时任务)
后端·asp.net
Rverdoser3 小时前
RabbitMQ的基本概念和入门
开发语言·后端·ruby
Tech Synapse4 小时前
Java根据前端返回的字段名进行查询数据的方法
java·开发语言·后端
.生产的驴4 小时前
SpringCloud OpenFeign用户转发在请求头中添加用户信息 微服务内部调用
spring boot·后端·spring·spring cloud·微服务·架构
微信-since811924 小时前
[ruby on rails] 安装docker
后端·docker·ruby on rails
代码吐槽菌6 小时前
基于SSM的毕业论文管理系统【附源码】
java·开发语言·数据库·后端·ssm