"{},{},{}".format(*(1,2,3,4,5))
打印:
'1,3'
只要格式中的{}数不超过元组的长度,这就有效.我想让它适用于任意长度的元组,如果长度不足则用-s填充它.为了避免对{}的数量做出假设,我想使用一个生成器.这就是我的想法:
def tup(*args): for s in itertools.chain(args,itertools.repeat('-')): yield s print "{},{}".format(*tup(1,2))
预期:
'1,-'
但它永远不会回归.你能用发电机吗?有更好的方法吗?
解决方法
如果格式只是采用一个序列而不是需要单独的参数,你可以通过构建一个正确的序列来解决这个问题.这是一个简单的例子:
class DefaultList(list): def __getitem__(self,idx): try: return super(DefaultList,self).__getitem__(idx) except IndexError: return '-'
当然,你的真实版本将包装一个任意的可迭代,而不是子类列表,并且可能必须使用tee或内部缓存并按要求提取新值,只有在你通过结束时才是默认值. (您可能希望在ActiveState中搜索“惰性列表”或“延迟序列”配方,因为其中有一些可以执行此操作.)但这足以显示示例.
现在,这对我们有什么帮助?它没有; *在一个DefaultList上只会尝试从该东西中创建一个元组,为我们提供完全相同数量的参数.但是如果你有一个版本的格式可以只采取一系列的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,kwargs): try: return super(DefaultFormatter,self).get_value(key,kwargs) except IndexError: return '-' f = DefaultFormatter('-') print(f.vformat('{0} {2}',[0],{})) print(f.vformat('{0} {2}',[0,1,3],{}))
当然,你仍然需要将迭代器包装在提供Sequence协议的东西中.
在我们处理它的同时,如果语言具有“可迭代解包”协议,则可以更直接地解决您的问题.请参阅here,了解提出这样一个问题的python-ideas线程,以及该想法所带来的所有问题. (另请注意,格式化函数会使这更棘手,因为它必须直接使用解包协议而不是依赖于解释器来神奇地执行它.但是,假设它这样做,那么你只需要写一个非常简单和通用的包装器,可以处理__unpack__的任何迭代.)