多态性:Python用多元法泛化多态性

  面向对象编程多功能性有许多是通过多态性获得多态性是指:倘若有合适上下文区别类型对象可以用类似方式进行工作但大多数 OOP 编程是单分派(single dispatch);也就是说仅有个指定对象确定采用哪个代码路径从概念上来说较通用技术是允许/思路方法所有参数确定其专门化本文介绍了用 Python 进行多分派(multiple dispatch)实现并演示了用该实现生成更佳举例

  什么是多态性?

  使用 Python 或其它面向对象编程语言大多数员在使用多态性时都采用了种较为实用和具体方式也许多态性最常见应用是在创建符合公共协议系列对象方面在 Python 中这通常只是特别多态性问题;在其它语言中较为常见是声明形式接口和/或这些系列共享个公共祖先

  例如有许多都是对“类文件”对象进行操作其中只是通过支持类似 .read 、 .readlines 也许还有 .seek 这样几个思路方法来定义类文件类似 read_app_data 这样可能带有参数 src 当我们我们可能决定将该参数传递给本地文件、 urllib 对象、 cStringIO 对象还是些让该 src.read 定制对象从每个对象在 read_app_data 中如何运行这角度来看每个对象类型是可交换

  让我们回头想想这里面真正发生了什么事实上我们真正关心是在上下文中选择要执行正确代码路径;老式过程代码可以做出同样决定OOP 只不过使代码雅致了些例如个过程(伪)代码片断可能为如下所示:

  清单 1. 对象类型上代码路径过程选择

...bind 'src' in some manner...
<<src is a file object>>:
  read_from_file(src)
el <<src is a urllib object>>:
  read_from_url(src)
el <<src is a io object>>:
  read_from_io(src)
...etc...


  通过安排区别类型对象来执行公共思路方法我们将 分派决定移到对象中并从显式条件块中消除给定 src 对象通过查看整个继承树知道它需要个代码块隐式切换仍在继续执行但是它针对对象 src 类型进行

  对象 src 对于所有传递给其思路方法参数享有特权OOP 语义使该特权看起来似乎是必然其实不然在许多情况下过程切换只是被置于类思路方法主体中例如我们可以用伪 Python 实现协议兼容类 Foo 和 Bar 如下所示:

  清单 2. Foo 和 bar 实现 .meth 思路方法

Foo:
  def meth(self, arg):
     <<arg is a Foo>>:
      ...FooFoo code block...
    el <<arg is a Bar>>:
      ...FooBar code block...
Bar:
  def meth(self, arg):
     <<arg is a Foo>>:
      ...BarFoo code block...
    el <<arg is a Bar>>:
      ...BarBar code block...
# Function to utilize Foo/Bar single-dispatch polymorphism
def x_with_y(x, y):
   <<x is Foo or Bar>> and <<y is Foo or Bar>>:
    x.meth(y)
  :
    raise TypeError,"x, y must be either Foo's or Bar's"


   x_with_y可能要执行 5个截然区别代码路径/块如果 x 和 y 类型不合适则给出异常(当然您还可以做别事)但是假定类型没问题那么代码路径 首先由多态分派选中 其次由过程切换选中而且 Foo.meth 和 Bar.meth 定义内部切换在很大程度上是等同(单分派类型)多态性只做了工作

  完善多态性

  在单分派多态性中挑选出“拥有”思路方法对象从语法上说在 Python 中通过在点的前指定名称来挑选对象 - 跟在点、思路方法名和左括号后面只是个参数但是从语义上说对象特殊的处还在于利用继承树来进行思路方法解析

  如果不用种特定方式处理个对象而是允许代码块中所包含每个对象帮助选择正确代码路径那会怎样呢?例如我们可以用种更对称方式来表达 5路切换:

  清单 3. Foo 和 Bar 上多分派

x_with_y = Dispatch([((object, object), <<exception block>>)])
x_with_y.add_rule((Foo,Foo), <<FooFoo block>>)
x_with_y.add_rule((Foo,Bar), <<FooBar block>>)
x_with_y.add_rule((Bar,Foo), <<BarFoo block>>)
x_with_y.add_rule((Bar,Bar), <<BarBar block>>)
#...call the function x_with_y using some arguments...
x_with_y(something, otherthing)


  我认为对多个参数进行多态分派所具有这种对称性比先前样式要雅致得多还有对于确定要采取适当代码路径时所涉及两个对象该样式有助于记录它们同等作用

  标准 Python 不允许配置这种类型多分派;但幸运您可以使用我所编写模块 multimethods 来做到这请参阅 参考资料以下载该模块本身或将其作为 Gnosis 实用部分旦安装了 multimethods 的后您需要做是在应用顶部包含这样行代码:

  from multimethods import Dispatch

  “多元法(multimethods)”通常是多分派同义词;但是多元法这个名称暗示着处理较抽象概念时应采用具体/对象

  Dispatch 例子是个可对象可以用数量不限规则来配置它还可以用思路方法 Dispatch.remove_rule 来删除规则这使得使用 multimethods 多分派比静态类层次结构更加具有动态性(但是您也可以在运行时用 Python 类做些隐秘事)还要注意 Dispatch 例子可以接受数目不定参数;首先对参数数目进行匹配其次是其类型如果用规则中不曾定义任何模式来 Dispatch 例子则出现 TypeError 如果您只想在遇到未定义情况时抛出异常那么就没必要使用落后 (object,object) 模式对 x_with_y 进行

  只要将 Dispatch 中所列出每个 (pattern,function) 元组传递给 .add_rule 思路方法;在化时建立规则还是在后来建立规则员觉得哪种方便就采用哪种(可以将它们进行混合再匹配就像前面举例那样)从分派器分派器中使用参数传递给该;您需要确保您使用可以接受和该匹配参数数目例如以下这两种是等价:

  清单 4. 显式和分派

# Define function, es, objects
def func(a,b): pr "The X is", a, "the Y is", b
X(object): pass
Y(object): pass
x, y = X, Y
# Explicit call to func with args
func(x,y)
# Dispatched call to func _disibledevent= dispatcher.clone
  #...do up activities...
  dispatcher(some, rule, pattern)
  #...do other stuff...


  如果在 threadable_dispatch 中没有生成新线程那就切正常了

  您花点时间就可以理解多分派思想了如果您精通面向对象编程那就更不在话下了但是应用它段时间后您可能会发现多分派从开始就泛化并增强了 OOP 胜过过程编程优势



Tags:  什么是多态性 dna多态性 基因多态性 多态性

延伸阅读

最新评论

发表评论