python实现泛型函数
泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型。 ——来自百度
简易理解
泛型函数就是你定义函数的时候, 能接收万能类型, 在调用时, 会根据传入值本身的类型进行区分处理, 达到某些效果, 好处是代码复用率高, 减少代码冗余, 对面向对象语言中泛型函数概念非常常用.
接下来使用到的py库 functools 中的 singledispatch 模块
使用方法
在需要进行泛型的函数上加上装饰器即可
from functools import singledispatch
@singledispatch
def add(obj):
return obj
- 1 singledispatch : 标记处理函数传值类型
- 2 register(类型): 为传值判断类型后输出结果
- 3 后续使用无需写函数名, 只要有register(类型装饰器)即可调用
- 4 定义需要判断的类型int str tuple dict list set 根据自己需求
函数中实现类型判断
from functools import singledispatch
@singledispatch
def add(obj):
return obj
int类型
@add.register(int)
def _(add):
print("int类型")
@add.register(str)
def _(add):
print("str类型")
@add.register(list)
def _(add):
print("list类型")
@add.register(tuple)
def _(add):
print("tuple类型")
@add.register(dict)
def _(add):
print("dict类型")
@add.register(set)
def _(add):
print("set类型")
add([1,2,3])
输出结果: list类型
根据输入的内容进行判断类型输出
对象中使用
from functools import singledispatch
class Type:
@singledispatch
def add(obj):
return obj
@add.register(int)
def _(add):
print("int类型")
@add.register(str)
def _(add):
print("str")
@add.register(list)
def _(add):
print("list类型")
@add.register(tuple)
def _(add):
print("tuple类型")
@add.register(dict)
def _(add):
print("dict类型")
@add.register(set)
def _(add):
print("set类型")
Type.add([1,2,3])
输出结果:list类型
不调用singledispatch模块实现泛型函数
这里需要实现一个类型拼接操作, 如下代码
在此之前需要先定义一个装饰器, 来判断两个类型是否相同, 如果不同则不作后续判断, 节省资源消耗
def check_type(func):
def wrapper(*args, **kwargs):
args1, args2 = args[:2]
if type(args1) != type(args2):
return "两种类型不一致, 不能做拼接"
return func(*args, **kwargs)
return wrapper
@check_type
def add(obj1, obj2):
if isinstance(obj1,list):
obj1 += obj2
return obj1
if isinstance(obj1, str):
obj1 += obj2
return obj1
if isinstance(obj1, tuple):
obj1 += obj2
return obj1
if isinstance(obj1, dict):
obj1 += obj2
return obj1
print(add([1, 2, 3], [1, 2, 3]))
结果与上方一样, 按需选择
例子很简单, 最后多用于tcp/ip接收判断使用
提示: bool类型也是可以的,完!
Python泛型思考
近日在学习Python内容时学习到了泛型,但从个人看法来说Python泛型与Java的泛型有很大的不同,在此提出一点个人的看法
首先,针对Java的泛型,其主要作用是作为某些以后才指定类型的替代,在编写过程中这些泛型可以在实例化过程中由参数指定,典型例子如集合类当中的泛型
List<String> list = new ArrayList<String>()
这就相当于指定了该集合类的新类型。泛型使用的原因是可以加强类型转化的安全性以及减少转换的次数。比如在上例中的List集合中,如果从中取出一个元素,在未指明泛型的前提下,取出的类型元素只能是Object,必须使用强制类型转换转化为对应的类型才能供后续代码使用。
那么,此处就可能存在问题,因为没有指明泛型,那么意味着加入集合的时候只要你的元素类型是Object即可加入,由于在Java中Object为最高基类,意味着任何元素都可加入泛型当中,由此,没有任何办法保证你取出的元素一定是你想要的的类型,所以此时为保证程序健壮性必须处理ClassCastException异常;但在指明泛型后,由于出入都可以限制元素类型,所以减少了此种转换的异常,也就保证了转换的安全性。
由以上描述可以知道,泛型首先要求的是你能够在实例化时指定类型,所以泛型一般应用于强类型的语言当中才比较好用,但Python本身是弱类型语言,所以Python的泛型并不完全是这种作用
Python的泛型类Generic的注释中提到,
A generic type is typically declared by inheriting from an instantiation of this class with one or more type variables.
也就是说,Python 的泛型类型是继承这个类之后才会声明,这种声明方式与Python的抽象类声明方式十分类似。以IO下的三个实现类为例,其声明分别为
class IO(Generic[AnyStr]):
class BinaryIO(IO[bytes]):
class TextIO(IO[str]):
从这些定义中可以看出,在声明泛型类之后IO类便可以使用泛型的方式去作为其他类的基类定义,
并且AnyStr在Python的类型声明中是包含了bytes与str两类的,由此我们可以发现Python的泛型与Java泛型的一个最根本区别:Python 的泛型是在声明时就指定了泛型类型,也就是说,Python的泛型类型主要作用是:某个类存在多种使用场景,并且我们可以预知各个使用场景的类型,为了将原始代码能够广泛应用于其他场景上使用泛型去保障代码在各个场景上的通用性。因此,在泛型类的声明中并不像其他语言一样使用类似T的方式去替代类型,而是直接使用已经声明的泛型类型在代码中书写,如readline函数的定义
@abstractmethod
def readline(self, limit: int = -1) -> AnyStr:
pass
由此,我们可以归纳Python泛型的两个条件:
1.继承Generic类,并在类的参数中指明泛型类型
2.在实现中使用泛型类型参与代码编写
最后,由于在声明时就已经指定了泛型的类型,所以Python泛型更大程序上我认为是一个具有辅助说明的功能,相当于说明在编写当中告诉编程人员应当使用什么类型,这其实从另一个层面上也是在其他语言中泛型功能的一大体现
以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程网。