IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Python知识库 -> python: methoddispatch -> 正文阅读

[Python知识库]python: methoddispatch

参考链接:

Python methoddispatch包_程序模块 - PyPI - Python中文网

functools.singledispatchmethod(Python 3.8) - 知乎

摘要:本文章介绍了methoddispatch包的基本使用,以及如果在类外注册泛型函数,泛型函数的分派机制,通过属性调用查看指定类型会被分派的执行函数,查看泛型函数的所有注册函数,子类重写扩展父类的泛型函数,在单个实例上进行指定类型函数的重写等;简单提及python3.8中的functools.singledispatchmethod

1. methoddispatch包简介

? ? ? ? python3.4向functools标准库中添加了singledispatch装饰器(主要针对函数),而methoddispatch 包则将此项功能添加到了实例方法中。

2. 什么是泛型函数?

????????泛型函数是指由多个函数组成的函数,可以对不同类型实现相同的操作,调用时应该使用哪个实现由分派算法决定

3. methoddispatch包的使用

from methoddispatch import singledispatch, SingleDispatch
from decimal import Decimal


class MyClass(SingleDispatch):
    @singledispatch
    def func(self, arg, verbose=False):
        if verbose:
            print("Let me just say,", end=" ")
        print(arg)

    @func.register(int)
    def func_int(self, arg, verbose=False):
        if verbose:
            print("Strength in numbers, eh?", end=" ")
        print(arg)

    @func.register(list)
    def func_list(self, arg, verbose=False):
        if verbose:
            print("Enumerate this:")
        for i, elem in enumerate(arg):
            print(i, elem)

    @func.register(float)
    @func.register(Decimal)
    def func_num(self, arg, verbose=False):
        if verbose:
            print("Half of your number:", end=" ")
        print(arg / 2)

若要定义泛型方法的定义,使用@singledispatch修饰;分派发生在第一个参数的类型上,相应的创建函数。要向函数添加重载实现,使用泛型函数的register()属性;它是一个装饰器,获取一个类型参数并装饰一个实现该类型操作的函数。

register()属性仅在类语句中工作,依赖于SingleDispatch.__init_subclass__创建实际调度表。这也意味着无法注册具有相同名称的两个方法,因为只有最后一个将出现在类字典中。

未定义在类中的函数想注册到泛型函数可以使用 add_overload 属性

def nothing(obj, args, verbose=False):
    print("Nothing. ")

MyClass.func.add_overload(type(None), nothing)

当泛型函数被调用时,会根据传入的第一个参数的类型进行分派

>>> a = MyClass()
>>> a.func("Hello, world.")  
Hello, world.
>>> a.func("test.", verbose=True) 
Let  me just say, test.
>>> a.func(42, verbose=True)    
Strength in numbers, eh? 
>>> a.func(['spam', 'spam', 'eggs', 'spam'], verbose=True)  
Enumerate this:
0 spam
1 spam
2 eggs
3 spam
>>> a.func(None)
Nothing
>>> a.func(1.23)
0.615

如果特定类型没有注册的实现,则使用其方法解析顺序来查找更通用的实现。用@singledispatch修饰的原始函数注册为基object类型,这意味着如果找不到更好的实现,就使用它。

在检查泛型函数将为给定类型选择哪个实现,请使用dispatch()属性

>>> a.func.dispatch(flost)
<function MyClass.func_num at 0x000002C0E535F950>
>>> a.func.dispatch(dict)
<function MyClass.func at 0x000002C0E5355510>

要访问所有注册的实现,请使用只读的registry属性

>>> a.func.registry.keys()
dict_keys([<class 'object'>, <class 'int'>, <class 'list'>, <class 'decimal.Decimal'>, <class 'float'>, <class 'NoneType'>])
>>> a.func.registry[float]
<function MyClass.func_num at 0x000002236A7FF950>
>>> a.func.registry[object]
<function MyClass.func at 0x000002236A7F5510>

子类可以用它们自己的重写扩展基类上函数的类型注册表。SingleDispatch minix类确保每个子类都有自己独立的调度注册表副本

class SubClass(MyClass):
    @MyClass.func.register(str)
    def func_str(self, arg, verbose=False):
        print("Str.")


>>> a = MyClass()
>>> a.func("hello")   
hello
>>> b = SubClass()
>>> b.func("hello")
Str.

方法重写不需要再次提供 register 装饰器

class SubClass2(MyClass):
    def func_int(self, arg, verbose=False):
        print("Int")

>>> c = SubClass2()
>>> c.func_int(100)
Int

但是,为register decorator提供相同的类型也可以。用不同类型装饰一个方法重写(不是一个好主意)将被注册成不同的类型,并为原始类型保留基类处理程序。

如果需要,可以在单个实例上指定方法重写

def func_str(arg, verbose=False):
    print("String.")


>>> d = MyClass()
>>> d.func.register(str, func_str)

>>> d.func("Hello! ")
String.
>>> e = MyClass()
>>> e.func("Hello! ")
Hello! 

在Python3.6及更高版本中,对于用类型注释的函数,修饰符将自动推断第一个参数的类型

class MyClassAnno(SingleDispatch):
    @singledispatch
    def func(self, arg):
        print("Default.")

    @func.register
    def func_int(self, arg: int):
        print("Int.")


class SubClassAnno(MyClassAnno):
    @MyClassAnno.func.register
    def func_str(self, arg: str):
        print("Str.")

在Python3.5和更早版本中,SingleDispatch 类使用一个元类SingleDispatchMeta来管理调度注册表。但是在python3.6和更高版本中,使用了__init_subclass__方法。如果您的类也继承自ABC接口,那么您可以在python3.5及更高版本中使用SingleDispatchABCMeta元类。

最后,通过类访问方法func, 将使用该类的调度注册表

>>> SubClass2.func(s, 1)
Subclass int
>>> MyClass.func(s, 1)
1

4. 在python3.8中,可以通过使用functools.singledispatchmethod

class Negator:
    @singledispatchmethod
    @classmethod
    def neg(cls, arg):
        raise NotImplementedError("Cannot negate a")

    @neg.register
    @classmethod
    def _(cls, arg: int):
        return -arg

    @neg.register
    @classmethod
    def _(cls, arg: bool):
        return not arg

  Python知识库 最新文章
Python中String模块
【Python】 14-CVS文件操作
python的panda库读写文件
使用Nordic的nrf52840实现蓝牙DFU过程
【Python学习记录】numpy数组用法整理
Python学习笔记
python字符串和列表
python如何从txt文件中解析出有效的数据
Python编程从入门到实践自学/3.1-3.2
python变量
上一篇文章      下一篇文章      查看所有文章
加:2022-01-08 13:57:17  更:2022-01-08 13:59:19 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/16 3:25:50-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码