简单的泛型函数(类似于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需要64位jdk 1.5 for windows   eclipse运算符+对于参数类型java是未定义的。双,爪哇。双人   未下载文件扩展名为的java文件   java不支持带有POST的媒体类型   从动态创建的多个EditText读取文本时发生java错误   java无法为同一xpath单击多个按钮   如何在Java中动态格式化字符串   java Android Clear Middle活动   多线程Java内存模型volatile和x86   git在Java中通过Jgit忽略文件或文件夹   java“决策无法区分输入的备选方案1、2…”   子类的javajpa继承   java需要弄清楚如何操作mutator来弄清楚一个类,教授说,我对如何操作感到困惑   java如何使用JDBC将数据从文件复制到PostgreSQL?