"{}, {}, {}".format(*(1,2,3,4,5))
打印:
'1, 2, 3'
只要{}
中format
的数量不超过元组的长度,这就有效。我想让它适用于任意长度的元组,如果它的长度不够,则用-
s填充它。为了避免对{}
的数量进行假设,我想使用一个生成器。这就是我的想法:
def tup(*args):
for s in itertools.chain(args, itertools.repeat('-')):
yield s
print "{}, {}, {}".format(*tup(1,2))
预期:
'1, 2, -'
但它永远不会回来。你能用发电机吗?有更好的方法吗?
答案 0 :(得分:4)
您不能使用无限生成器来填充任何 *args
任意参数调用。
Python迭代生成器以加载所有参数以传递给callable,如果生成器是无限的,那将永远不会完成。
您可以毫无问题地使用非无限生成器。您可以使用itertools.islice()
限制生成器:
from itertools import islice
print "{}, {}, {}".format(*islice(tup(1,2), 3))
毕竟,您已经知道模板有多少个插槽。
答案 1 :(得分:3)
Martijn Pieters有即时答案,但如果您想为format
自动填充创建某种通用包装器/助手,您可以查看string.Formatter.parse
。使用它,您可以获得format
如何查看格式字符串的表示,并去掉参数count / named参数名称以动态计算迭代器需要多长时间。
答案 2 :(得分:3)
如果你考虑一下,除了变量参数解包一次解包的事实之外,还有一个事实是format
不一定按顺序接受它的参数,如'{2} {1} {0}'
。 / p>
如果format
只是采用一个序列而不是需要单独的参数,你可以通过构建一个做正确事情的序列来解决这个问题。这是一个简单的例子:
class DefaultList(list):
def __getitem__(self, idx):
try:
return super(DefaultList, self).__getitem__(idx)
except IndexError:
return '-'
当然,您的真实版本将包装任意可迭代,而不是子类list
,并且可能必须使用tee
或内部缓存并根据请求提取新值,仅在默认情况下默认你已经过了结束。 (您可能希望在ActiveState中搜索“惰性列表”或“延迟序列”配方,因为其中有一些可以执行此操作。)但这足以显示示例。
现在,这对我们有什么帮助?它没有; *lst
上的DefaultList
只会尝试从该事物中产生一个元组,给出我们已经拥有的完全相同数量的参数。但是如果你有format
的版本可以只采用一系列args呢?然后你可以通过你的DefaultList
,它会起作用。
你确实拥有:Formatter.vformat
。
>>> string.Formatter().vformat('{0} {1} {2}', DefaultList([0, 1]), {})
'0 1 -'
但是,一旦您明确使用Formatter
而不是通过str
方法隐式使用,就会有更简单的方法。您可以覆盖其get_value
方法和/或其check_unused_args
:
class DefaultFormatter(string.Formatter):
def __init__(self, default):
self.default = default
# Allow excess arguments
def check_unused_args(self, used_args, args, kwargs):
pass
# Fill in missing arguments
def get_value(self, key, args, kwargs):
try:
return super(DefaultFormatter, self).get_value(key, args, kwargs)
except IndexError:
return '-'
f = DefaultFormatter('-')
print(f.vformat('{0} {2}', [0], {}))
print(f.vformat('{0} {2}', [0, 1, 2, 3], {}))
当然,你仍然需要将迭代器包装在提供Sequence协议的东西中。
虽然我们正在使用它,但如果语言具有“可迭代解包”协议,则可以更直接地解决您的问题。请参阅here以获取提出此类事情的python-ideas线程,以及该想法所具有的所有问题。 (另请注意,format
函数会使这更棘手,因为它必须直接使用解包协议而不是依赖解释器来神奇地执行它。但是,假设它这样做,那么你只需要为任何处理__unpack__
的迭代编写一个非常简单和通用的包装器。)
答案 3 :(得分:1)
天真的方法是为格式函数提供L / 2参数,其中L是格式字符串的长度。由于替换令牌的长度至少为2个字符,因此您肯定总是有足够的值来解压缩:
def tup(l, *args):
for s in args + (('-',) * l):
yield s
s = "{}, {}, {}"
print s.format(*list(tup(len(s)//2, 1, 2)))
根据Silas Ray的建议,可以使用string.Formatter.parse
找到更精确的上限import string
def tup(l, *args):
for s in args + (('-',) * l):
yield s
s = "{}, {}, {}"
l = len(list(string.Formatter().parse(s)))
print s.format(*list(tup(l, 1, 2)))