类似函数的变量

时间:2014-02-06 21:18:18

标签: python function variables representation

[灵感来自this question]

假设我有两个列表:

list1 = ['tom', 'mary', 'frank', 'joe', 'john', 'barry']
list2 = [1, 2, 3, 4]

我想将list1中的每个名称与list2中的数字相匹配。由于list2中有四个数字,我希望将前四个名称中的每一个与list2中的相应数字配对,并将随机数分配给list1中的其余名称。< / p>

我知道我可以使用enumeraterandom.choice的for循环解决此问题。实际上,我已经为原始问题提供了such a solution 我想知道,如果有可能做这样的事情:

for name, number in itertools.izip_longest(list1, list2, fillvalue=MAGIC):
    print name, number

最初,我想过使用这样的东西:

MAGIC = random.choice(list1)

但是,首先执行random.choice(list1),然后将答案用作压缩操作的fillvalue。这没有吸引力,因为它没有为它拉链的每对值选择一个新的随机值。因此很明显,itertools.izip_longest需要fillvalue,它本身就有一个值,它不会调用它。实际上,如果我要为它提供一个函数,它将产生一个由名称和可调用函数组成的对,它也是低调的。因此,lambda函数不是可行的解决方案。

如何在调用某个函数时创建调用某个函数的变量? itertools.izip_longest如何使用fillvalue变量?是否调用了该变量的__repr__?如果是这样,我可以创建一个类__repr__来调用其中的函数吗?

2 个答案:

答案 0 :(得分:8)

似乎这里最简单的方法是创建一个生成所有填充值永恒的生成器,然后将其链接到生成list2中的值:

def inf_gen(f):
    while True:
        yield f()

请注意,inf_gen(f)实际上等同于iter(f, None),因为f永远不会返回。带有两个参数的iter调用第一个参数,直到它返回第二个参数。

然后使用它:

>>> from itertools import izip, chain
>>> for name, number in izip(list1,chain(list2, iter(lambda: random.choice(list2), None))):
    print name, number

tom 1
mary 2
frank 3
joe 4
john 1
barry 4

您也可以使用itertools来完成此操作,而无需使用itertools.count生成器理解来定义单独的函数:

>>> from itertools import izip, chain, count
>>> for name, number in izip(list1, chain(list2, (random.choice(list2) for _ in count()))):
    print name, number

答案 1 :(得分:3)

如果你想让它“缩放”到多个迭代器,你可以稍微修改http://docs.python.org/2.7/library/itertools.html?highlight=izip_longest#itertools.izip_longest中给出的代码来做到这一点:

from itertools import repeat, chain, count

class ZipExhausted(Exception):
    pass

def izip_longest2(*args, **kwds):
    fillvalue = kwds.get('fillvalue')
    fillgen = kwds.get('fillgen', repeat(fillvalue))  # added
    counter = [len(args) - 1]
    def sentinel():
        if not counter[0]:
            raise ZipExhausted
        counter[0] -= 1
        yield next(fillgen)  # modified
    iterators = [chain(it, sentinel(), fillgen) for it in args]  # modified
    try:
        while iterators:
            yield tuple(map(next, iterators))
    except ZipExhausted:
        pass


a = ['bob', 'mary', 'paul']
b = ['eggs', 'spam']
c = ['a', 'b', 'c', 'd']

for x in izip_longest2(a, b, c, fillgen=count()):
    print '\t'.join(map(str, x))

# output:
# bob   eggs    a
# mary  spam    b
# paul  0   c
# 1 2   d