【问题标题】:Can generators be used with string.format in python?生成器可以与 python 中的 string.format 一起使用吗?
【发布时间】:2013-08-30 14:43:51
【问题描述】:
"{}, {}, {}".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, -'

但它永远不会回来。你能让它与发电机一起工作吗?有更好的方法吗?

【问题讨论】:

    标签: python string format generator


    【解决方案1】:

    如果你想一想,除了变量参数解包会同时解包的事实之外,还有一个事实是format 不一定按顺序排列它的参数,就像在'{2} {1} {0}' 中一样。

    如果format 只是采用一个序列而不是需要单独的参数,您可以通过构建一个执行正确操作的序列来解决此问题。这是一个简单的例子:

    class DefaultList(list):
        def __getitem__(self, idx):
            try:
                return super(DefaultList, self).__getitem__(idx)
            except IndexError:
                return '-'
    

    当然,您的实际版本会包装任意可迭代,而不是子类 list,并且可能必须使用 tee 或内部缓存并根据请求拉入新值,仅在您通过时默认结束。 (您可能想在 ActiveState 中搜索“惰性列表”或“惰性序列”配方,因为其中有一些这样做。)但这足以显示示例。

    现在,这对我们有什么帮助?它没有; *lstDefaultList 上只会尝试从事物中创建一个元组,从而为我们提供与我们已经拥有的完全相同数量的参数。但是如果你有一个 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], {}))
    

    当然,您仍然需要将迭代器包装在提供序列协议的东西中。


    虽然我们这样做了,但如果该语言具有“可迭代解包”协议,则可以更直接地解决您的问题。请参阅here 以了解提出此类问题的 python-ideas 线程,以及该想法存在的所有问题。 (另请注意,format 函数会使这个变得更棘手,因为它必须直接使用解包协议而不是依赖解释器来神奇地完成它。但是,假设它这样做了,那么你只需要编写一个非常简单且通用的包装器,用于处理任何处理 __unpack__ 的可迭代对象。)

    【讨论】:

      【解决方案2】:

      您不能使用无限生成器来填充 任何 *args 任意参数调用。

      Python 遍历生成器以加载所有参数以传递给可调用对象,如果生成器是无限的,那将永远不会完成。

      您可以毫无问题地使用无限生成器。您可以使用itertools.islice() 来限制生成器:

      from itertools import islice
      
      print "{}, {}, {}".format(*islice(tup(1,2), 3))
      

      毕竟,您已经知道您的模板有多少个插槽。

      【讨论】:

      • 知道了。你能推荐一个更好的方法吗?我不满意生成某个最大长度的生成器,这是浪费的(违背了使用生成器的目的,一个列表就可以了)并且不能保证总是工作。
      • @user443854:您可以使用itertools.islice() 来限制生成器。
      • 我知道itertools.islice(),但我看不出它在这里是如何应用的。在我可以使用它之前,我需要知道所需的元素数量。我希望实现一些不同的东西。用简单的英语,我想告诉解释器:这是一个生成器,可以根据需要迭代它多次,但不会更多。
      • @user443854:实际上有一个关于“变量参数解包”协议的python-ideas讨论:一种特殊方法__unpack__(self, n)。当您尝试将可迭代解包到元组赋值、* 函数调用等时,它会首先尝试i.__unpack__(n),如果没有这样的方法,则回退到通常的迭代。您可能需要阅读该主题以了解对它的反对意见,因为它基本上就是您所要求的。
      • @user443854:请参阅here 了解主线程(尽管 IIRC 有几个衍生产品,如果你想要整个讨论,你必须自己找到)。
      【解决方案3】:

      Martijn Pieters 有直接的答案,但如果您想为format 自动填充创建某种通用包装器/帮助器,您可以查看string.Formatter.parse。使用它,您可以获得format 如何查看格式字符串的表示,并去除参数计数/命名参数名称以动态计算您的迭代器需要多长时间。

      【讨论】:

        【解决方案4】:

        天真的方法是向格式函数提供 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)))
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2016-03-12
          • 2016-08-10
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-08-09
          • 1970-01-01
          相关资源
          最近更新 更多