创建长的多行字符串的 Pythonic 方法

我有一个很长的查询。我想在 Python 中将其分成几行。用 JavaScript 做到这一点的一种方法是使用几个句子,然后用+运算符将它们连接起来(我知道,这可能不是最有效的方法,但是我并不真正关心此阶段的性能,只是代码可读性)。例:

var long_string = 'some text not important. just garbage to' +
                  'illustrate my example';

我尝试在 Python 中执行类似的操作,但没有成功,因此我使用\拆分了长字符串。但是,我不确定这是否是唯一 / 最佳 / 最佳的方法。看起来很尴尬。实际代码:

query = 'SELECT action.descr as "action", '\
    'role.id as role_id,'\
    'role.descr as role'\
    'FROM '\
    'public.role_action_def,'\
    'public.role,'\
    'public.record_def, '\
    'public.action'\
    'WHERE role.id = role_action_def.role_id AND'\
    'record_def.id = role_action_def.def_id AND'\
    'action.id = role_action_def.action_id AND'\
    'role_action_def.account_id = ' + account_id + ' AND'\
    'record_def.account_id=' + account_id + ' AND'\
    'def_id=' + def_id

答案

您在谈论多行字符串吗?容易,使用三引号将它们开始和结束。

s = """ this is a very
        long string if I had the
        energy to type more and more ..."""

您也可以使用单引号(当然在开始和结束时使用 3 个单引号),并将生成的字符串s与其他任何字符串一样对待。

注意 :与任何字符串一样,引号和结尾引号之间的任何内容都将成为字符串的一部分,因此本示例中有一个前导空格(如 @ root45 所指出)。该字符串还将包含空格和换行符。

即:

' this is a very\n        long string if I had the\n        energy to type more and more ...'

最后,还可以像这样在 Python 中构造长行:

s = ("this is a very"
      "long string too"
      "for sure ..."
     )

其中将包含任何额外的空格或换行符(这是一个有意的示例,显示了跳过空格会导致什么结果):

'this is a verylong string toofor sure ...'

不需要逗号,只需将要连接的字符串放在一对括号中,并确保考虑到任何需要的空格和换行符。

如果您不希望使用多行字符串,而只需要一个长的单行字符串,则可以使用括号,只需确保在字符串段之间不包含逗号,那么它将是一个元组。

query = ('SELECT   action.descr as "action", '
         'role.id as role_id,'
         'role.descr as role'
         ' FROM '
         'public.role_action_def,'
         'public.role,'
         'public.record_def, '
         'public.action'
         ' WHERE role.id = role_action_def.role_id AND'
         ' record_def.id = role_action_def.def_id AND'
         ' action.id = role_action_def.action_id AND'
         ' role_action_def.account_id = '+account_id+' AND'
         ' record_def.account_id='+account_id+' AND'
         ' def_id='+def_id)

在您正在构造的 SQL 语句中,多行字符串也可以。但是,如果多行字符串将包含额外的空格将是一个问题,那么这将是实现所需功能的好方法。

\换行对我有用。这是一个例子:

longStr = "This is a very long string " \
        "that I wrote to help somebody " \
        "who had a question about " \
        "writing long strings in Python"

我发现自己对此很满意:

string = """This is a
very long string,
containing commas,
that I split up
for readability""".replace('\n',' ')

我发现在构建长字符串时,通常会执行诸如构建 SQL 查询之类的事情,在这种情况下,这是最好的:

query = ' '.join((  # note double parens, join() takes an iterable
    "SELECT foo",
    "FROM bar",
    "WHERE baz",
))

莱文的建议是好的,但可能容易出错:

query = (
    "SELECT foo"
    "FROM bar"
    "WHERE baz"
)

query == "SELECT fooFROM barWHERE baz"  # probably not what you want

您还可以在使用 “” 符号时串联变量:

foo = '1234'

long_string = """fosdl a sdlfklaskdf as
as df ajsdfj asdfa sld
a sdf alsdfl alsdfl """ +  foo + """ aks
asdkfkasdk fak"""

编辑:找到了一种更好的方法,命名为 params 和. format():

body = """
<html>
<head>
</head>
<body>
    <p>Lorem ipsum.</p>
    <dl>
        <dt>Asdf:</dt>     <dd><a href="{link}">{name}</a></dd>
    </dl>
    </body>
</html>
""".format(
    link='http://www.asdf.com',
    name='Asdf',
)

print(body)

此方法使用:

  • 只需一个反斜杠即可避免初始换行
  • 通过使用三引号引起来的字符串,几乎没有内部标点符号
  • 使用textwrap inspect模块去除局部缩进
  • account_iddef_id变量使用 python 3.6 格式的字符串插值('f')。

这种方式对我来说似乎是最 pythonic 的。

# import textwrap  # See update to answer below
import inspect

# query = textwrap.dedent(f'''\
query = inspect.cleandoc(f'''
    SELECT action.descr as "action", 
    role.id as role_id,
    role.descr as role
    FROM 
    public.role_action_def,
    public.role,
    public.record_def, 
    public.action
    WHERE role.id = role_action_def.role_id AND
    record_def.id = role_action_def.def_id AND
    action.id = role_action_def.action_id AND
    role_action_def.account_id = {account_id} AND
    record_def.account_id={account_id} AND
    def_id={def_id}'''
)

更新 :1/29/2019 合并 @ShadowRanger 的建议使用inspect.cleandoc代替textwrap.dedent

在 Python> = 3.6 中,您可以使用格式化字符串文字(f 字符串)

query= f'''SELECT   action.descr as "action"
    role.id as role_id,
    role.descr as role
    FROM
    public.role_action_def,
    public.role,
    public.record_def,
    public.action
    WHERE role.id = role_action_def.role_id AND
    record_def.id = role_action_def.def_id AND
    action.id = role_action_def.action_id AND
    role_action_def.account_id = {account_id} AND
    record_def.account_id = {account_id} AND
    def_id = {def_id}'''

例如:

sql = ("select field1, field2, field3, field4 "
       "from table "
       "where condition1={} "
       "and condition2={}").format(1, 2)

Output: 'select field1, field2, field3, field4 from table 
         where condition1=1 and condition2=2'

如果 condition 的值应该是字符串,则可以这样:

sql = ("select field1, field2, field3, field4 "
       "from table "
       "where condition1='{0}' "
       "and condition2='{1}'").format('2016-10-12', '2017-10-12')

Output: "select field1, field2, field3, field4 from table where
         condition1='2016-10-12' and condition2='2017-10-12'"

我个人发现以下是用Python编写原始 SQL 查询的最佳方式(简单,安全和 Pythonic),尤其是在使用Python 的 sqlite3 模块时

query = '''
    SELECT
        action.descr as action,
        role.id as role_id,
        role.descr as role
    FROM
        public.role_action_def,
        public.role,
        public.record_def,
        public.action
    WHERE
        role.id = role_action_def.role_id
        AND record_def.id = role_action_def.def_id
        AND action.id = role_action_def.action_id
        AND role_action_def.account_id = ?
        AND record_def.account_id = ?
        AND def_id = ?
'''
vars = (account_id, account_id, def_id)   # a tuple of query variables
cursor.execute(query, vars)   # using Python's sqlite3 module

优点

  • 简洁的代码(Pythonic!)
  • 防止 SQL 注入
  • 与 Python 2 和 Python 3 兼容(毕竟是 Pythonic)
  • 无需字符串连接
  • 无需确保每行的最右字符是一个空格

缺点

  • 由于查询中的变量由?代替?占位符,跟踪哪个可能会变得有点困难?当查询中有很多 Python 变量时,用替换。