【问题标题】:A function-like variable类函数变量
【发布时间】:2014-03-04 01:36:51
【问题描述】:

[灵感来自this question]

假设我有两个列表:

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

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

我知道我可以使用带有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__ 创建一个在其中调用函数的类吗?

【问题讨论】:

  • “我将如何创建一个在调用某个函数时调用它的变量?” - 你不会。你会调用一个函数。
  • 你可以使用属性获得你想要的对象属性,而在 Python 3 中,你可以使用讨厌的元类魔法在类范围内获得你想要的东西,但是对于常规变量,你不能去做吧。
  • @user2357112:是的,但是当“调用”. Thus, if __repr__` 是调用一些外部函数时,很多类的实例都会显示它们的__repr__ 值,然后突然之间,你有一个变量,其中包含一个实例,其值由函数确定。否则,我确实熟悉变量和函数之间的区别。
  • izip_longest 不调用repr。它只是直接吐出对象。
  • @inspectorG4dget:您真的不希望__repr__ 在每次调用时都返回不同的值。此外,即使这样做了,izip_longets 方法仍然不起作用,因为填充值是在调用函数时确定的,而不是每次填充时确定的。

标签: python function variables representation


【解决方案1】:

如果您希望它“缩放”到多个迭代器,您可以对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

【讨论】:

  • 请修正缩进?
  • 编辑:固定缩进,感谢您指出,@inspectorG4dget
  • 这实际上非常出色!谢谢你:)
【解决方案2】:

似乎这里最简单的方法是创建一个生成器,为永恒生成所有填充值,然后将其与生成 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

【讨论】:

  • iter 的两个参数形式本质上就是inf_gen
  • @chepner:太好了!完全忘记了iter。将更新答案
猜你喜欢
  • 2023-04-08
  • 2021-12-22
  • 2020-06-08
  • 2017-04-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-22
  • 2013-10-08
相关资源
最近更新 更多