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
32 ответа
Вы говорите о многострочных строках? Легко, используйте тройные кавычки, чтобы начать и закончить их.
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"
Я обнаружил, что при построении длинных строк вы обычно делаете что-то вроде создания 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
Я нашел себя счастливым с этим:
string = """This is a
very long string,
containing commas,
that I split up
for readability""".replace('\n',' ')
Этот подход использует только одну обратную косую черту, чтобы избежать начального перевода строки, почти без внутренней пунктуации при использовании строки в тройных кавычках, удаляет локальные отступы с помощью модуля textwrap, а также использует интерполяцию строки в формате python 3.6 ('f') для account_id
а также def_id
переменные. Этот способ выглядит наиболее питонным для меня.
import textwrap
query = textwrap.dedent(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}'''
)
Вы также можете объединять переменные при использовании нотации """:
foo = '1234'
long_string = """fosdl a sdlfklaskdf as
as df ajsdfj asdfa sld
a sdf alsdfl alsdfl """ + foo + """ aks
asdkfkasdk fak"""
РЕДАКТИРОВАТЬ: нашел лучший способ, с именованными параметрами и.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)
Руководство по стилю PEP 8 рекомендует использовать круглые скобки:
Предпочтительным способом переноса длинных строк является использование подразумеваемого Python продолжения строки внутри круглых и фигурных скобок. Длинные строки можно разбивать на несколько строк, заключая выражения в круглые скобки. Их следует использовать вместо использования обратной косой черты для продолжения строки.
Пример:
long_string = (
"This is a lengthy string that takes up a lot of space. I am going to "
"keep on typing words to fill up more and more space to show how you can "
"split the string across multiple lines."
)
В 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}'''
Я нахожу textwrap.dedent
лучше всего подходит для длинных струн, как описано здесь:
def create_snippet():
code_snippet = textwrap.dedent("""\
int main(int argc, char* argv[]) {
return 0;
}
""")
do_something(code_snippet)
Например:
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'"
Другие уже упоминали метод круглых скобок, но я хотел бы добавить, что с круглыми скобками разрешены встроенные комментарии.
Прокомментируйте каждый фрагмент:
nursery_rhyme = (
'Mary had a little lamb,' # Comments are great!
'its fleece was white as snow.'
'And everywhere that Mary went,'
'her sheep would surely go.' # What a pesky sheep.
)
Комментарий не разрешен после продолжения:
При использовании продолжения строки с обратной косой чертой (\
), комментарии не допускаются. Вы получите SyntaxError: unexpected character after line continuation character
ошибка.
nursery_rhyme = 'Mary had a little lamb,' \ # These comments
'its fleece was white as snow.' \ # are invalid!
'And everywhere that Mary went,' \
'her sheep would surely go.'
# => SyntaxError: unexpected character after line continuation character
Лучшие комментарии для строк Regex:
Основываясь на примере с https://docs.python.org/3/library/re.html,
a = re.compile(
r'\d+' # the integral part
r'\.' # the decimal point
r'\d*' # some fractional digits
)
# Using VERBOSE flag, IDE usually can't syntax highight the string comment.
a = re.compile(r"""\d + # the integral part
\. # the decimal point
\d * # some fractional digits""", re.X)
В качестве общего подхода к длинным строкам в Python вы можете использовать тройные кавычки, split
а также join
:
_str = ' '.join('''Lorem ipsum dolor sit amet, consectetur adipiscing
elit, sed do eiusmod tempor incididunt ut labore et dolore
magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation
ullamco laboris nisi ut aliquip ex ea commodo.'''.split())
Выход:
'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo.'
Что касается вопроса OP, касающегося SQL-запроса, ответ ниже игнорирует правильность этого подхода к построению SQL-запросов и фокусируется только на построении длинных строк в удобочитаемом и эстетичном виде без дополнительного импорта. Это также не учитывает вычислительную нагрузку, которую это влечет.
Используя тройные кавычки, мы создаем длинную и читаемую строку, которую затем разбиваем на список, используя split()
тем самым удаляя пробелы, а затем объединяйте их вместе с ' '.join()
. Наконец, мы вставляем переменные, используяformat()
команда:
account_id = 123
def_id = 321
_str = '''
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 = {}
'''
query = ' '.join(_str.split()).format(account_id, account_id, def_id)
Производит:
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 = 123 AND record_def.account_id=123 AND def_id=321
Изменить: этот подход не соответствует PEP8, но иногда я считаю его полезным
Добавление к ответу @Levon ....
1. Создайте многострочную строку следующим образом:
paragraph = """this is a very
long string if I had the
energy to type more and more ..."""
print(paragraph)
Выход:
'this is a very\n long string if I had the\n energy to type more and more ...'
В этой строке будут новые строки и пробелы. Так что удали их.
2. Удалите лишние пробелы с помощью регулярного выражения.
paragraph = re.sub('\s+', ' ', paragraph)
print(paragraph)
Выход:
'this is a very long string if I had the energy to type more and more ...'
Лично я считаю, что лучшим (простым, безопасным и Pythonic) способом написания необработанных SQL-запросов на Python является следующий, особенно при использовании модуля sqlite3 в 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 = ?
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
Pros
- Аккуратный и простой код (Pythonic!)
- Сейф от SQL-инъекций
- Совместим с Python 2 и Python 3 (это Pythonic в конце концов)
- Конкатенация строк не требуется
- Не нужно гарантировать, что самый правый символ каждой строки является пробелом
Cons
- Поскольку переменные в запросе заменены на
?
заполнитель, может быть немного трудно отслеживать, какие?
должна быть заменена на какую переменную Python, когда их много в запросе.
tl;dr: использование """\
а также """
обернуть строку, как в
string = """\
This is a long string
spanning multiple lines.
"""
Из официальной документации по питону:
Строковые литералы могут занимать несколько строк. Одним из способов является использование тройных кавычек: "" "..." "" или ""...... ". Конец строк автоматически включается в строку, но это можно предотвратить, добавив \ в конце строки. Следующий пример:
print("""\
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
""")
производит следующий вывод (обратите внимание, что начальный перевод строки не включен):
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
ммм.
Я знаю, что прошло много времени с тех пор, как этот вопрос был опубликован. Но я только что нашел стиль, который хотел бы использовать для назначения длинных и многострочных строк переменным в моих проектах. Это требует немного дополнительного времени выполнения, но по-прежнему сохраняет красоту кода, даже если переменная, которой я присваиваю свою строку, имеет большой отступ.
# Suppose the following code is heavily indented
line3header = "Third"
variable = fr"""
First line.
Second line.
{line3header} line.
{{}} line.
...
The last line.
"""
variable = variable.strip()
variable = variable.format("Fourth")
variable += "\n"
Там идет.
Я обычно использую что-то вроде этого:
text = '''
This string was typed to be a demo
on how could we write a multi-line
text in Python.
'''
Если вы хотите удалить раздражающие пробелы в каждой строке, вы можете сделать следующее:
text = '\n'.join(line.lstrip() for line in text.splitlines())
Ваш реальный код не должен работать, вам не хватает пробелов в конце "строк" (например: role.descr as roleFROM...
)
Для многострочной строки есть тройные кавычки:
string = """line
line2
line3"""
Он будет содержать разрывы строк и лишние пробелы, но для SQL это не проблема.
Эй, попробуйте что-то вроде этой надежды, это работает, как в этом формате, он вернет вам непрерывную строку, как вы успешно спросили об этом свойстве`
"message": f'you have successfully inquired about '
f'{enquiring_property.title} Property owned by '
f'{enquiring_property.client}'
Объединение идей из:
Левон или Джесси, Фахил и Дарскотт
с моим предложением форматирования вы можете написать свой запрос как:
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
)
vars = (account_id, account_id, def_id) # a tuple of the query variables
cursor.execute(query, vars) # using Python's sqlite3 module
или как:
vars = []
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 = '
vars.append(account_id) or '?'
' AND'
' record_def.account_id = '
vars.append(account_id) or '?'
' AND'
' def_id = '
vars.append(def_id) or '?'
)
cursor.execute(query, tuple(vars)) # using Python's sqlite3 module
Что может быть интересно вместе с 'IN' и 'vars.extend(options) или n_options(len(options))', где:
def n_options(count):
return '(' + ','.join(count*'?') + ')'
Или с подсказкой от darkfeline, что вы все еще можете ошибаться с этими ведущими пробелами и разделителями, а также с именованными заполнителями:
SPACE_SEP = ' '
COMMA_SEP = ', '
AND_SEP = ' AND '
query = SPACE_SEP.join((
'SELECT',
COMMA_SEP.join((
'action.descr as "action"',
'role.id as role_id',
'role.descr as role',
)),
'FROM',
COMMA_SEP.join((
'public.role_action_def',
'public.role',
'public.record_def',
'public.action',
)),
'WHERE',
AND_SEP.join((
'role.id = role_action_def.role_id',
'record_def.id = role_action_def.def_id',
'action.id = role_action_def.action_id',
'role_action_def.account_id = :account_id',
'record_def.account_id = :account_id',
'def_id = :def_id',
)),
))
vars = {'account_id':account_id,'def_id':def_id} # a dictionary of the query variables
cursor.execute(query, vars) # using Python's sqlite3 module
См. Документацию по Cursor.execute-function.
"Это [самый питонический] путь!" - ...
Я знаю, что это довольно старый вопрос, но Python за это время изменился, и я не вижу этого ответа, так что поехали.
Другой способ - использовать \, чтобы вырезать текущую строку и перейти к другой:
print("This line will \
get carried over to\
the new line.\
Notice how this\
word will be together because \
of no space around it")
Вы также можете поместить SQL-заявление в отдельный файл action.sql
и загрузить его в файл py с
with open('action.sql') as f:
query = f.read()
Таким образом, SQL-операторы будут отделены от кода Python. Если в операторе sql есть параметры, которые нужно заполнить из python, вы можете использовать форматирование строки (например,%s или {field})
Путь "а ля" Скала (но я думаю, что это самый питонический путь, как того требует OQ):
description = """
| The intention of this module is to provide a method to
| pass meta information in markdown_ header files for
| using it in jinja_ templates.
|
| Also, to provide a method to use markdown files as jinja
| templates. Maybe you prefer to see the code than
| to install it.""".replace('\n | \n','\n').replace(' | ',' ')
Если вы хотите, чтобы окончательная строка без линий перехода, просто поставьте \n
в начале первого аргумента второго замените:
.replace('\n | ',' ')`.
Примечание: белая линия между "... шаблонами". и "Кроме того..." требует пробела после |
,
Другой вариант, который я считаю более читабельным, когда код (например, переменная) имеет отступ, а выходная строка должна быть однострочной (без новых строк):
def some_method():
long_string = """
a presumptuous long string
which looks a bit nicer
in a text editor when
written over multiple lines
""".strip('\n').replace('\n', ' ')
return long_string
Из официальной документации по питону:
Строковые литералы могут занимать несколько строк. Одним из способов является использование тройных кавычек: """...""" или ""...... ". Конец строк автоматически включается в строку, но это можно предотвратить, добавив \ в конце строки. Следующий пример:
print("""\
Usage: thingy [OPTIONS]
-h Display this usage message
-H hostname Hostname to connect to
""")
производит следующий вывод (обратите внимание, что начальный перевод строки не включен):
Используйте тройные кавычки. Люди часто используют их для создания строк документации в начале программы, чтобы объяснить их цель и другую информацию, имеющую отношение к ее созданию. Люди также используют их в функциях, чтобы объяснить назначение и применение функций. Пример:
'''
Filename: practice.py
File creator: me
File purpose: explain triple quotes
'''
def example():
"""This prints a string that occupies multiple lines!!"""
print("""
This
is
a multi-line
string!
""")
Для определения длинной строки внутри dict,сохраняя символы новой строки, но опуская пробелы, я закончил тем, что определил строку в такой константе:
LONG_STRING = \
"""
This is a long sting
that contains newlines.
The newlines are important.
"""
my_dict = {
'foo': 'bar',
'string': LONG_STRING
}
Я использую рекурсивную функцию для построения сложных запросов SQL. Этот метод обычно может использоваться для создания больших строк при сохранении читабельности кода.
# Utility function to recursively resolve SQL statements.
# CAUTION: Use this function carefully, Pass correct SQL parameters {},
# TODO: This should never happen but check for infinite loops
def resolveSQL(sql_seed, sqlparams):
sql = sql_seed % (sqlparams)
if sql == sql_seed:
return ' '.join([x.strip() for x in sql.split()])
else:
return resolveSQL(sql, sqlparams)
PS: взгляните на потрясающую библиотеку python-sqlparse, чтобы при необходимости распечатывать запросы SQL. http://sqlparse.readthedocs.org/en/latest/api/
Мне нравится этот подход, потому что он дает право на чтение. В тех случаях, когда у нас длинные струны, это невозможно! В зависимости от уровня отступа вы находитесь и до сих пор ограничены 80 символами в строке... Ну... Больше ничего не нужно говорить. На мой взгляд, руководства по питонскому стилю все еще очень расплывчаты. Я выбрал подход @Eero Aaltonen, потому что он дает преимущество в чтении и здравом смысле. Я понимаю, что руководства по стилю должны помочь нам, а не сделать нашу жизнь беспорядочной. Спасибо!
class ClassName():
def method_name():
if condition_0:
if condition_1:
if condition_2:
some_variable_0 =\
"""
some_js_func_call(
undefined,
{
'some_attr_0': 'value_0',
'some_attr_1': 'value_1',
'some_attr_2': '""" + some_variable_1 + """'
},
undefined,
undefined,
true
)
"""