python – 一个更快的嵌套元组列表和返回

我正在尝试执行元组列表并列出对未知深度和形状的嵌套序列的元组转换.这些电话正在进行数十万次,这就是我试图尽可能多地挤出速度的原因.

任何帮助深表感谢.

这是我到目前为止所拥有的……

def listify(self, seq, was, toBe):
  temp = []
  a = temp.append
  for g in seq:
    if type(g) == was:
      a(self.listify(g, was, toBe))
    else:
      a(g)
  return toBe(temp)

并且要求列表元组的调用如下所示:

self.listify((...), tuple, list)

编辑:是的,我完全错过了枚举(来自旧的实现)并忘记键入else部分.

谢谢你们两位的帮助.我可能会选择协同程序.

解决方法:

我最近和coroutines一起工作很安静.优点是可以减少方法调用的开销.将新值发送到协程比调用函数更快.虽然你不能创建一个递归协程,它会抛出一个ValueError:生成器已经执行但你可以创建一个协同工作池 – 你需要一个工作者为树的每个级别.我已经制作了一些可行的测试代码,但尚未查看时序问题.

def coroutine(func):
    """ A helper function decorator from Beazley"""
    def start(*args, **kwargs):
        g = func(*args, **kwargs)
        g.next()
        return g
    return start

@coroutine
def cotuple2list():
    """This does the work"""
    result = None
    while True:
        (tup, co_pool) = (yield result)
        result = list(tup)
        # I don't like using append. So I am changing the data in place.
        for (i,x) in enumerate(result):
            # consider using "if hasattr(x,'__iter__')"
            if isinstance(x,tuple):
                result[i] = co_pool[0].send((x, co_pool[1:]))


@coroutine
def colist2tuple():
    """This does the work"""
    result = None
    while True:
        (lst, co_pool) = (yield result)
        # I don't like using append so I am changing the data in place...
        for (i,x) in enumerate(lst):
            # consider using "if hasattr(x,'__iter__')"
            if isinstance(x,list):
                lst[i] = co_pool[0].send((x, co_pool[1:]))
        result = tuple(lst)

来自HYRY帖子的纯Python替代品:

def list2tuple(a):
    return tuple((list2tuple(x) if isinstance(x, list) else x for x in a))
def tuple2list(a):
    return list((tuple2list(x) if isinstance(x, tuple) else x for x in a))

建立一个协同程序池 – 这是一个池的黑客,但它的工作原理:

# Make Coroutine Pools
colist2tuple_pool = [colist2tuple() for i in xrange(20) ]
cotuple2list_pool = [cotuple2list() for i in xrange(20) ]

现在做一些时间 – 比较:

def make_test(m, n):
    # Test data function taken from HYRY's post!
    return [[range(m), make_test(m, n-1)] for i in range(n)]
import timeit
t = make_test(20, 8)
%timeit list2tuple(t)
%timeit colist2tuple_pool[0].send((t, colist2tuple_pool[1:]))

结果 – 注意第二行’s’旁边的’u’:-)

1 loops, best of 3: 1.32 s per loop
1 loops, best of 3: 4.05 us per loop

真的太快了,不敢相信.有人知道timeit是否与协同程序一起使用?
这是老式的方式:

tic = time.time()
t1 = colist2tuple_pool[0].send((t, colist2tuple_pool[1:]))
toc = time.time()
print toc - tic

结果:

0.000446081161499

较新版本的Ipython和%timit会发出警告:

The slowest run took 9.04 times longer than the fastest. This could
mean that an intermediate result is being cached 1000000 loops, best
of 3: 317 ns per loop

经过一些进一步的调查,python生成器不是魔术,发送仍然是一个函数调用.我的基于生成器的方法看起来更快的原因是我在列表上进行了一个就地操作 – 这导致更少的函数调用.

在最近的talk中,我写了很多额外的细节.

希望这可以帮助那些希望玩发电机的人.

上一篇:如何用正确的顺序在Python中构造嵌套字典理解?


下一篇:python – 连接嵌套元组