Python中的链式字符串格式

时间:2010-07-16 21:02:12

标签: python string

在处理一些小的SQL格式时,我惊讶地发现我可以链接字符串格式化器:

def get_sql(table, limit=True):
    sql = "select report_date from %s"
    if limit:
        result = "%s limit 1" % sql % table
    else:
        result = sql % table
    return result
这是合法的吗?有什么理由不这样做?

4 个答案:

答案 0 :(得分:4)

它之所以有意义,是因为这样的陈述:

'some value goes here %s' % value

实际上返回一个字符串。这样查看它可能更合乎逻辑:

result = ("%s limit 1" % sql) % table

这样做并没有明显的错误,但链接操作符可能会导致出现错误的问题。

例如,这样可以正常工作:

>>> sql = 'a value of %s'
>>> x = 'some string %s with stuff'
>>> y = 'VALUE'
>>> x % sql % y
'some string a value of VALUE with stuff'

但是如果那里有格式化错误(我意识到这个例子是病态的,但它得到了重点):

>>> sql = 'a value of %d'
>>> x = 'some string %d with stuff'
>>> y = 123    
>>> x % sql % y
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: %d format: a number is required, not str

目前尚不清楚哪个%d导致了您的错误。出于这个原因,我会把它拆分出去,如果可能的话,每行只使用一个%格式化器,因为回溯将能够指向你到底哪一行以及哪个格式化器有问题。

为了记录,通过每行一个格式化程序,您还可以让其他任何必须阅读您的代码并试图找出正在发生的事情的人更轻松。

答案 1 :(得分:3)

这是完全合法的。

字符串格式化程序的“single argument”形式实际上是一种特殊情况 - 对于多个项目,通常使用元组,这将导致一个更明显的例子,说明为什么它没问题

result = "%s limit 1" % (sql % (table,),)

这个^最初是为了鼓励提问者,支持多种格式是一种合法的语言功能,但正如Nas Banov评论的那样,它确实读起来就像我试图解释它是如何工作的(没有帮助拧紧)代码)。它没有像这样建议从右到左构建字符串,但是从左到右构建它(是关联的)。操作符必须在左侧获取一个字符串并返回一个字符串,但可以在右侧使用非字符串(元组)。由于你不能在一对元组上使用%,它不可能反向工作

>>> "%s %f %s" % ( "%d", 0.1, "%d %d" ) % (1,2,3)
'1 0.100000 2 3'
然而,它可能导致复杂/混乱的代码,所以我个人非常谨慎地使用它。

你可以这样做你的例子:

def get_sql(table, limit=True):
    sql = "select report_date from"
    strlimit = ""
    if limit:
        strlimit = "limit 1"
    return "%s %s"%(sql, strlimit)

答案 2 :(得分:2)

为什么是的,可以像这样链接%字符串格式,即使这是我第一次看到它使用(并且以可怕的方式,请注意)!

原因是相同类型的运算符group left to right(具有“左关联性” - 除了取幂**和比较a<b<c之外的明显例外。)

所以就像

一样
>>> 1 - 2 - 3    # equals to (1-2)-3
-4
>>> 16 / 4 / 2   # equals to (16 /4) /2,  NOT 16 / (4 / 2)
2

s1 % s2 % s3等于(s1 % s2) % s3

哦,顺便说一下,如果s1,s2和s3是字符串或数字并不重要 - 编译器不知道在编译期间只有运行时,将确定%是否意味着“余数来自除法“(如果s1是数字)或字符串格式化(如果s1是字符串)。

答案 3 :(得分:0)

我会这样写:

def get_sql(table,limit=True):
    sql = "select report_date from %s"%table
    if limit: sql += " limit 1"
    return sql

PS。您发布的代码的工作方式如下:

In [49]: "%s limit 1" % sql
Out[49]: 'select report_date from %s limit 1'

In [50]: "%s limit 1" % sql % 'table'
Out[50]: 'select report_date from table limit 1'

当然你可以做到,但我认为不是特别清楚。