##language:zh #pragma section-numbers on ''' yield 的学习,模拟无限数据 ''' ::-- ZoomQuiet [<>] <> ## 默许导航,请保留 <> {{{Albert Lee hide details 12:08 pm (2 minutes ago) reply-to python-cn@googlegroups.com to "Python.cn@google" date Oct 24, 2007 12:08 PM subject [CPyUG:34110] yield 的学习,模拟无限数据 mailed-by googlegroups.com }}} = FPy 模拟 = == yield 的学习,模拟无限数据 == 对haskell我最喜爱的特性是惰性计算和无限数据结构,以及函数组合。 这些特性在python中是否可以模拟出来呢? 今天作了一些尝试 `python中提供了yield 和 decorators`, 应当可以模拟出。 === 尝试: 无限数据结构 === {{{ haskell: [1..] Hugs> take 5 [1..] [1,2,3,4,5] }}} Python: {{{ >>> def inf_list1(): i = 0 while 1: i += 1 yield i >>> def take(n, it): cnt = 0 for i in it(): cnt += 1 if cnt > n: break yield i >>> take(5, m) >>> [i for i in take(5, inf_list1)] [1, 2, 3, 4, 5] }}} Python 的 take 也实现为一个 generator ,这样的好处是可以串起来执行,比如,我要实现 haskell中的: Hugs> drop 3 $ take 5 [1..] [4,5] * 那么再实现一个 drop 函数: {{{ >>> def drop(n, it): t = 0 for i in it(): t += 1 if t > n: yield i >>> def m10(): for i in range(10): yield i >>> [i for i in drop(3, m10)] [3, 4, 5, 6, 7, 8, 9] >>> [i for i in take(5, m10)] [0, 1, 2, 3, 4] >>> }}} * 不过,在组合 take 和 drop 的时候遇到了麻烦 {{{ >>> drop(3, take(5, m10)) >>> [i for i in drop(3, take(5, m10))] Traceback (most recent call last): File "", line 1, in -toplevel- [i for i in drop(3, take(5, m10))] File "", line 3, in drop for i in it(): TypeError: 'generator' object is not callable >>> }}} * 修改下 drop, take 的定义如下: {{{ >>> def take(n, it): cnt = 0 if callable(it): it=it() for i in it: cnt += 1 if cnt > n: break yield i >>> def drop(n, it): cnt = 0 if callable(it): it = it() for i in it: cnt += 1 if cnt > n: yield i >>> [i for i in take(2, drop(3, take(7, inf_list1)))] [4, 5] >>> }}} === 对应 haskell === {{{ Hugs> take 2 $ drop 3 $ take 7 [1..] [4,5] Hugs> }}} 基本达到目的。 === 用itertools模块更简单 === {{{Qiangning Hong hide details 12:57 pm (8 minutes ago) reply-to python-cn@googlegroups.com to python-cn@googlegroups.com date Oct 24, 2007 12:57 PM subject [CPyUG:34115] Re: yield 的学习,模拟无限数据: }}} {{{!python import sys from itertools import count, islice def inf_list(): return count(1) def take(n, it): return islice(it, n) def drop(n, it): return islice(it, n, sys.maxint) list(take(5, inf_list()) -> [1, 2, 3, 4, 5] list(drop(3, take(5, inf_list()))) -> [4, 5] list(take(2, drop(3, take(7, count(1))))) -> [4, 5] }}} == 函数的组合 == 比较简单:{{{ Hugs> ((*2) . (+3)) 5 16 }}} * 在Python{{{ >>> def m2(x): return x * 2 >>> def add3(x): return x + 3 >>> def compose(f, g): return lambda x:f(g(x)) >>> compose(m2, add3) at 0x012875F0> >>> compose(m2, add3)(5) 16 >>> }}} === 对compose的装饰: === `infix 来自 cookbook` {{{ class Infix: def __init__(self, function): self.function = function def __ror__(self, other): return Infix(lambda x, self=self, other=other: self.function(other, x)) def __or__(self, other): return self.function(other) def __rlshift__(self, other): return Infix(lambda x, self=self, other=other: self.function(other, x)) def __rshift__(self, other): return self.function(other) def __call__(self, value1, value2): return self.function(value1, value2) # compose def compose(f, g): return lambda x:f(g(x)) o=Infix(compose) add2 = lambda x:x+2 multi3 = lambda x:x*3 new_f = add2 |o| multi3 print new_f(3) --- >>> (add2 <> multi3) (3) 11 }}} 已经比较接近了 === curry === 一个函数需要两个参数, 只给出一个参数的话,则返回一个函数,再给一个参数才计算(curry) , 用 decorators 貌似可以实现。 对多参数的处理不知道怎么办了。 组合现在可以这样: {{{ >>> f = fun1 <> fun2 <> fun3 >>> f(1) }}} 看来函数重载真是有很多意想不到的作用,可以实现 DSL了。 {{{#!python from functools import partial def allow_partial_args(func): def _(*args): rturn partial(func, *args) return _ @allow_partial_args def add(a, b): return a + b add(1)(2) -> 3 add()(1, 2) -> 3 add(1, 2)() -> 3 }}} == 反馈 ==