2010-07-16 83 views
4

格式化处理有点SQL格式化我惊奇地发现我可以链字符串格式化:链式字符串在Python

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

这是有道理的,它的作品,因为像这样的语句:

'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导致您的错误。出于这个原因,如果可能的话,我会把它分开,每行只使用一个%格式化程序,因为那么追溯程序将能够指出你到底是哪一行以及哪一个格式化程序存在问题。

对于记录来说,通过每行创建一个格式化程序,您还可以让任何需要阅读代码并尝试弄清楚发生了什么的人都轻松得多。

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

PS:

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) 
+0

'--':错误的解释,这与多个参数无关,关联性错误。尝试使用'“%ss limit 1'%'%'%'BOO'来查看我的意思,这个表达式可以工作,只要我们按照您的建议放置括号,''%ss limit 1'%('%'%( 'BOO'))'中断/错误。此外,您提出的修补程序并不比原来的 – 2010-07-17 05:19:32

+0

好,我认为您误解了。我并不是说这与单数或多重的论点有什么关系,只是如果你从使用单数转换为元组,这将变得更加清楚,这是一个合法的事情。你的反例是错的 - ('%'%('BOO'))无效。 ''%s limit 1'%'%s'%'BOO''对''%s限制1“%('%s'%('BOO'))'。两者都有效。请注意,问题不包含您的示例需要的'%ss'格式。这不是一个'建议的修复' - 原始代码没有问题,它只是一个建议的修改。 – pycruft 2010-07-17 23:36:06

+0

似乎你不明白。 (A)按照您所做的方式放置括号会更改操作**的顺序。当你有类型'A%B%C'的表达时,它被执行为'(A%B)%C',而不是'A%(B%C)',因为你的第一套参数迫使它。 (B)另外,你的理解是把表达式放在表达式之外使得元组不正确是错误的 - 事实并非如此。为了强制元组,你必须明确地使用构造函数tuple(),或者使用“愚蠢的逗号”,比如''%s limit 1“%(sql%(table,),)' - 这会创建元组,你的例子仍然是错的,因为(A) – 2010-07-18 07:20:29

0

我会这样写。你发布的代码是这样的:

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' 

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

+0

大声笑,你为什么甚至需要使用%格式? ;-) (虽然比原来好得多) – 2010-07-17 05:21:53

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是字符串)。