简单的泛型函数(类似于python自己的len()、pickle.dump()等)

simplegeneric的Python项目详细描述


simplegeneric模块允许您定义简单的单分派 泛型函数,类似于Python的内置泛型函数,比如 len()iter()等等但是,不是使用 特别命名的方法,这些泛型函数使用简单的查找 表,类似于由例如pickle.dump()和其他 在python标准库中找到的泛型函数。

从上面的例子可以看出,泛型函数实际上是 在Python中已经很常见了,但是没有标准的方法来创建 简单的这个库试图填补这个空白,作为泛型 函数是一个excellent alternative to the Visitor pattern,如 以及作为适应的最常用的替代品

这个库试图成为泛型 函数,因此它避免使用多个或谓词 调度,以及避免加速技术,如c调度 或者代码生成。但它绝对没有依赖性,除了 python 2.4,实现只是 少于100行

用法

定义和使用泛型函数很简单:

>>> from simplegeneric import generic
>>> @generic
... def move(item, target):
...     """Default implementation goes here"""
...     print("what you say?!")

>>> @move.when_type(int)
... def move_int(item, target):
...     print("In AD %d, %s was beginning." % (item, target))

>>> @move.when_type(str)
... def move_str(item, target):
...     print("How are you %s!!" % item)
...     print("All your %s are belong to us." % (target,))

>>> zig = object()
>>> @move.when_object(zig)
... def move_zig(item, target):
...     print("You know what you %s." % (target,))
...     print("For great justice!")

>>> move(2101, "war")
In AD 2101, war was beginning.

>>> move("gentlemen", "base")
How are you gentlemen!!
All your base are belong to us.

>>> move(zig, "doing")
You know what you doing.
For great justice!

>>> move(27.0, 56.2)
what you say?!

继承和允许的类型

为同一类型或对象定义多个方法是错误的:

>>> @move.when_type(str)
... def this_is_wrong(item, target):
...     pass
Traceback (most recent call last):
...
TypeError: <function move...> already has method for type <...'str'>

>>> @move.when_object(zig)
... def this_is_wrong(item, target): pass
Traceback (most recent call last):
  ...
TypeError: <function move...> already has method for object <object ...>

when_type()decorator只接受类或类型:

>>> @move.when_type(23)
... def move_23(item, target):
...     print("You have no chance to survive!")
Traceback (most recent call last):
  ...
TypeError: 23 is not a type or class

为超类型定义的方法按照MRO顺序继承:

>>> class MyString(str):
...     """String subclass"""

>>> move(MyString("ladies"), "drinks")
How are you ladies!!
All your drinks are belong to us.

也支持经典类实例(尽管查找过程 比新样式实例慢):

>>> class X: pass
>>> class Y(X): pass

>>> @move.when_type(X)
... def move_x(item, target):
...     print("Someone set us up the %s!!!" % (target,))

>>> move(X(), "bomb")
Someone set us up the bomb!!!

>>> move(Y(), "dance")
Someone set us up the dance!!!

多种类型或对象

为了方便起见,现在可以将多个类型或对象传递给 注册方法:

>>> @generic
... def isbuiltin(ob):
...     return False
>>> @isbuiltin.when_type(int, str, float, complex, type)
... @isbuiltin.when_object(None, Ellipsis)
... def yes(ob):
...     return True

>>> isbuiltin(1)
True
>>> isbuiltin(object)
True
>>> isbuiltin(object())
False
>>> isbuiltin(X())
False
>>> isbuiltin(None)
True
>>> isbuiltin(Ellipsis)
True

默认值和文档

可以使用函数的^{tt7}获取函数的默认实现$ 属性:

>>> @move.when_type(Y)
... def move_y(item, target):
...     print("Someone set us up the %s!!!" % (target,))
...     move.default(item, target)

>>> move(Y(), "dance")
Someone set us up the dance!!!
what you say?!

help()和其他文档工具将泛型函数视为普通函数 函数对象,具有与 原型/默认功能:

>>> help(move)
Help on function move:
...
move(*args, **kw)
    Default implementation goes here
...

检查和扩展

您可以使用 has_object()has_type()方法:

>>> move.has_object(zig)
True
>>> move.has_object(42)
False

>>> move.has_type(X)
True
>>> move.has_type(float)
False

注意,has_type()只查询是否有注册的方法 exact类型,而不是子类型或父类型:

>>> class Z(X): pass
>>> move.has_type(Z)
False
>您可以创建一个泛型函数,该函数从现有泛型继承 通过调用现有函数上的函数来执行函数:
>>> move2 = generic(move)
>>> move(2101, "war")
In AD 2101, war was beginning.

添加到新泛型函数的任何方法都重写 “基本”功能:

>>> @move2.when_type(X)
... def move2_X(item, target):
...     print("You have no chance to survive make your %s!" % (target,))

>>> move2(X(), "time")
You have no chance to survive make your time!

>>> move2(Y(), "time")
You have no chance to survive make your time!

注意,即使move()有一个类型为Y的方法,该方法 为move2()中的X定义优先。这是因为 move函数用作move2和^{tt19}的default方法$ 没有类型Y

的方法
>>> move2.default is move
True
>>> move.has_type(Y)
True
>>> move2.has_type(Y)
False

限制

  • 第一个参数始终用于分派,并且必须始终是 调用函数时按位置传递了
  • 文档工具看不到函数的原始参数签名,因此 你必须在文档字符串中描述它。
  • 如果有可选参数,则必须在 命令它们正常工作。(从好的方面来说,这意味着你可以 尽管依赖于 这种怪癖可能不是个好主意。)

如果我觉得有必要,这些限制可能会在以后的版本中取消。他们 需要像我这样生成运行时代码RuleDispatch, 不过,这有点痛苦。(或者我可以使用 BytecodeAssembler包来生成代码,因为这样做容易得多 使用基于字符串的代码生成,但这将引入更多 依赖关系,我尽量保持简单,这样我就可以 把它扔到钱德勒身上,不增加很大的脚印。)

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java我试图使用@OneToOne作为双向映射来映射实体,但却遇到了奇怪的异常   性能Java异步如何工作?异步方法似乎不是异步运行的   java这个代码可以更短吗   线程“main”Java中的csv Java ArrayList异常。lang.NegativeArraySizeException:28   java确定LayoutManager预布局中的显示视图   java如何在FirestorePagingAdapter中通过方法onLoadingStateChanged隐藏/显示进度条?   在Java中,如何打印一个类似于中间有“过道”的座位表的2d数组?   http Java实现字节范围服务,而不使用仅使用Java api的servlet   java无法使用命名根元素生成json   java如何在注销侦听器中获取http会话id?   数组内部输入(java)?   java如何为特殊情况提供更简单的构造函数   java在swing应用程序中显示JavaFX后台   java如何启用系统。出来在eclipse中运行Junit测试时使用println()?   如何在Java中实现Oracle用户定义的聚合函数