Как поставить одинарные кавычки в питоне
Перейти к содержимому

Как поставить одинарные кавычки в питоне

  • автор:

 

2. Lexical analysis¶

A Python program is read by a parser. Input to the parser is a stream of tokens, generated by the lexical analyzer. This chapter describes how the lexical analyzer breaks a file into tokens.

Python reads program text as Unicode code points; the encoding of a source file can be given by an encoding declaration and defaults to UTF-8, see PEP 3120 for details. If the source file cannot be decoded, a SyntaxError is raised.

2.1. Line structure¶

A Python program is divided into a number of logical lines.

2.1.1. Logical lines¶

The end of a logical line is represented by the token NEWLINE. Statements cannot cross logical line boundaries except where NEWLINE is allowed by the syntax (e.g., between statements in compound statements). A logical line is constructed from one or more physical lines by following the explicit or implicit line joining rules.

2.1.2. Physical lines¶

A physical line is a sequence of characters terminated by an end-of-line sequence. In source files and strings, any of the standard platform line termination sequences can be used — the Unix form using ASCII LF (linefeed), the Windows form using the ASCII sequence CR LF (return followed by linefeed), or the old Macintosh form using the ASCII CR (return) character. All of these forms can be used equally, regardless of platform. The end of input also serves as an implicit terminator for the final physical line.

When embedding Python, source code strings should be passed to Python APIs using the standard C conventions for newline characters (the \n character, representing ASCII LF, is the line terminator).

2.1.3. Comments¶

A comment starts with a hash character ( # ) that is not part of a string literal, and ends at the end of the physical line. A comment signifies the end of the logical line unless the implicit line joining rules are invoked. Comments are ignored by the syntax.

2.1.4. Encoding declarations¶

If a comment in the first or second line of the Python script matches the regular expression coding[=:]\s*([-\w.]+) , this comment is processed as an encoding declaration; the first group of this expression names the encoding of the source code file. The encoding declaration must appear on a line of its own. If it is the second line, the first line must also be a comment-only line. The recommended forms of an encoding expression are

which is recognized also by GNU Emacs, and

which is recognized by Bram Moolenaar’s VIM.

If no encoding declaration is found, the default encoding is UTF-8. In addition, if the first bytes of the file are the UTF-8 byte-order mark ( b’\xef\xbb\xbf’ ), the declared file encoding is UTF-8 (this is supported, among others, by Microsoft’s notepad).

If an encoding is declared, the encoding name must be recognized by Python (see Standard Encodings ). The encoding is used for all lexical analysis, including string literals, comments and identifiers.

2.1.5. Explicit line joining¶

Two or more physical lines may be joined into logical lines using backslash characters ( \ ), as follows: when a physical line ends in a backslash that is not part of a string literal or comment, it is joined with the following forming a single logical line, deleting the backslash and the following end-of-line character. For example:

A line ending in a backslash cannot carry a comment. A backslash does not continue a comment. A backslash does not continue a token except for string literals (i.e., tokens other than string literals cannot be split across physical lines using a backslash). A backslash is illegal elsewhere on a line outside a string literal.

2.1.6. Implicit line joining¶

Expressions in parentheses, square brackets or curly braces can be split over more than one physical line without using backslashes. For example:

Implicitly continued lines can carry comments. The indentation of the continuation lines is not important. Blank continuation lines are allowed. There is no NEWLINE token between implicit continuation lines. Implicitly continued lines can also occur within triple-quoted strings (see below); in that case they cannot carry comments.

2.1.7. Blank lines¶

A logical line that contains only spaces, tabs, formfeeds and possibly a comment, is ignored (i.e., no NEWLINE token is generated). During interactive input of statements, handling of a blank line may differ depending on the implementation of the read-eval-print loop. In the standard interactive interpreter, an entirely blank logical line (i.e. one containing not even whitespace or a comment) terminates a multi-line statement.

2.1.8. Indentation¶

Leading whitespace (spaces and tabs) at the beginning of a logical line is used to compute the indentation level of the line, which in turn is used to determine the grouping of statements.

Tabs are replaced (from left to right) by one to eight spaces such that the total number of characters up to and including the replacement is a multiple of eight (this is intended to be the same rule as used by Unix). The total number of spaces preceding the first non-blank character then determines the line’s indentation. Indentation cannot be split over multiple physical lines using backslashes; the whitespace up to the first backslash determines the indentation.

Indentation is rejected as inconsistent if a source file mixes tabs and spaces in a way that makes the meaning dependent on the worth of a tab in spaces; a TabError is raised in that case.

Cross-platform compatibility note: because of the nature of text editors on non-UNIX platforms, it is unwise to use a mixture of spaces and tabs for the indentation in a single source file. It should also be noted that different platforms may explicitly limit the maximum indentation level.

A formfeed character may be present at the start of the line; it will be ignored for the indentation calculations above. Formfeed characters occurring elsewhere in the leading whitespace have an undefined effect (for instance, they may reset the space count to zero).

The indentation levels of consecutive lines are used to generate INDENT and DEDENT tokens, using a stack, as follows.

Before the first line of the file is read, a single zero is pushed on the stack; this will never be popped off again. The numbers pushed on the stack will always be strictly increasing from bottom to top. At the beginning of each logical line, the line’s indentation level is compared to the top of the stack. If it is equal, nothing happens. If it is larger, it is pushed on the stack, and one INDENT token is generated. If it is smaller, it must be one of the numbers occurring on the stack; all numbers on the stack that are larger are popped off, and for each number popped off a DEDENT token is generated. At the end of the file, a DEDENT token is generated for each number remaining on the stack that is larger than zero.

Here is an example of a correctly (though confusingly) indented piece of Python code:

The following example shows various indentation errors:

(Actually, the first three errors are detected by the parser; only the last error is found by the lexical analyzer — the indentation of return r does not match a level popped off the stack.)

2.1.9. Whitespace between tokens¶

Except at the beginning of a logical line or in string literals, the whitespace characters space, tab and formfeed can be used interchangeably to separate tokens. Whitespace is needed between two tokens only if their concatenation could otherwise be interpreted as a different token (e.g., ab is one token, but a b is two tokens).

2.2. Other tokens¶

Besides NEWLINE, INDENT and DEDENT, the following categories of tokens exist: identifiers, keywords, literals, operators, and delimiters. Whitespace characters (other than line terminators, discussed earlier) are not tokens, but serve to delimit tokens. Where ambiguity exists, a token comprises the longest possible string that forms a legal token, when read from left to right.

2.3. Identifiers and keywords¶

Identifiers (also referred to as names) are described by the following lexical definitions.

The syntax of identifiers in Python is based on the Unicode standard annex UAX-31, with elaboration and changes as defined below; see also PEP 3131 for further details.

Within the ASCII range (U+0001..U+007F), the valid characters for identifiers are the same as in Python 2.x: the uppercase and lowercase letters A through Z , the underscore _ and, except for the first character, the digits 0 through 9 .

Python 3.0 introduces additional characters from outside the ASCII range (see PEP 3131). For these characters, the classification uses the version of the Unicode Character Database as included in the unicodedata module.

Identifiers are unlimited in length. Case is significant.

The Unicode category codes mentioned above stand for:

Lu — uppercase letters

Ll — lowercase letters

Lt — titlecase letters

Lm — modifier letters

Lo — other letters

Nl — letter numbers

Mn — nonspacing marks

Mc — spacing combining marks

Nd — decimal numbers

Pc — connector punctuations

Other_ID_Start — explicit list of characters in PropList.txt to support backwards compatibility

All identifiers are converted into the normal form NFKC while parsing; comparison of identifiers is based on NFKC.

A non-normative HTML file listing all valid identifier characters for Unicode 14.0.0 can be found at https://www.unicode.org/Public/14.0.0/ucd/DerivedCoreProperties.txt

2.3.1. Keywords¶

The following identifiers are used as reserved words, or keywords of the language, and cannot be used as ordinary identifiers. They must be spelled exactly as written here:

2.3.2. Soft Keywords¶

New in version 3.10.

Some identifiers are only reserved under specific contexts. These are known as soft keywords. The identifiers match , case and _ can syntactically act as keywords in contexts related to the pattern matching statement, but this distinction is done at the parser level, not when tokenizing.

As soft keywords, their use with pattern matching is possible while still preserving compatibility with existing code that uses match , case and _ as identifier names.

2.3.3. Reserved classes of identifiers¶

Certain classes of identifiers (besides keywords) have special meanings. These classes are identified by the patterns of leading and trailing underscore characters:

Not imported by from module import * .

In a case pattern within a match statement, _ is a soft keyword that denotes a wildcard .

Separately, the interactive interpreter makes the result of the last evaluation available in the variable _ . (It is stored in the builtins module, alongside built-in functions like print .)

Elsewhere, _ is a regular identifier. It is often used to name “special” items, but it is not special to Python itself.

The name _ is often used in conjunction with internationalization; refer to the documentation for the gettext module for more information on this convention.

It is also commonly used for unused variables.

System-defined names, informally known as “dunder” names. These names are defined by the interpreter and its implementation (including the standard library). Current system names are discussed in the Special method names section and elsewhere. More will likely be defined in future versions of Python. Any use of __*__ names, in any context, that does not follow explicitly documented use, is subject to breakage without warning.

Class-private names. Names in this category, when used within the context of a class definition, are re-written to use a mangled form to help avoid name clashes between “private” attributes of base and derived classes. See section Identifiers (Names) .

2.4. Literals¶

Literals are notations for constant values of some built-in types.

2.4.1. String and Bytes literals¶

String literals are described by the following lexical definitions:

One syntactic restriction not indicated by these productions is that whitespace is not allowed between the stringprefix or bytesprefix and the rest of the literal. The source character set is defined by the encoding declaration; it is UTF-8 if no encoding declaration is given in the source file; see section Encoding declarations .

In plain English: Both types of literals can be enclosed in matching single quotes ( ‘ ) or double quotes ( " ). They can also be enclosed in matching groups of three single or double quotes (these are generally referred to as triple-quoted strings). The backslash ( \ ) character is used to escape characters that otherwise have a special meaning, such as newline, backslash itself, or the quote character.

Bytes literals are always prefixed with ‘b’ or ‘B’ ; they produce an instance of the bytes type instead of the str type. They may only contain ASCII characters; bytes with a numeric value of 128 or greater must be expressed with escapes.

Both string and bytes literals may optionally be prefixed with a letter ‘r’ or ‘R’ ; such strings are called raw strings and treat backslashes as literal characters. As a result, in string literals, ‘\U’ and ‘\u’ escapes in raw strings are not treated specially. Given that Python 2.x’s raw unicode literals behave differently than Python 3.x’s the ‘ur’ syntax is not supported.

New in version 3.3: The ‘rb’ prefix of raw bytes literals has been added as a synonym of ‘br’ .

New in version 3.3: Support for the unicode legacy literal ( u’value’ ) was reintroduced to simplify the maintenance of dual Python 2.x and 3.x codebases. See PEP 414 for more information.

A string literal with ‘f’ or ‘F’ in its prefix is a formatted string literal; see Formatted string literals . The ‘f’ may be combined with ‘r’ , but not with ‘b’ or ‘u’ , therefore raw formatted strings are possible, but formatted bytes literals are not.

In triple-quoted literals, unescaped newlines and quotes are allowed (and are retained), except that three unescaped quotes in a row terminate the literal. (A “quote” is the character used to open the literal, i.e. either ‘ or " .)

Unless an ‘r’ or ‘R’ prefix is present, escape sequences in string and bytes literals are interpreted according to rules similar to those used by Standard C. The recognized escape sequences are:

Экранированные последовательности

Для полноценного представления структуры текста или его специфики нам нужны какие-то особые символы. Некоторые символы должны управлять курсором (еще называют «кареткой» – отголосок из прошлого от печатных машинок). Еще нужны какие-то символы с помощью которы можно выполнять какие-нибудь служебные задачи, например, обозначать шестнадцатеричные или восьмеричные коды символов. Для таких целей и существуют экранированные последовательности.

Экранированные последовательности — это последовательности, которые начинаются с символа » \ » за которым следует один или более символов.

Давайте сразу приведем пример:

Обратите внимание на то как функция print() осуществила вывод – в тех местах, где были последовательности ‘ \n ‘ она выполнила переносы строк. Вы, конечно же, догадались, что ‘ \n ‘ – это экранированная последовательность. Единственное, что стоит добавить так это то, что такие последовательности воспринимаются интерпретатором как единственный символ, т.е. несмотря на то что последовательность может состоять из нескольких символов ей соответствует всего один-единственный код. Например:

Таблица последовательностей

Экранированных последовательностей не так уж много, так что давайте сначала перечислим их все в таблице, а потом подробно рассмотрим назначение каждой из них.

Последовательность Назначение
\newline Если после символа » \ » сразу нажать клавишу Enter то это позволит продолжать запись с новой строки.
\\ Позволяет записать символ обратного слеша.
\’ Позволяет записать один символ апострофа.
Позволяет записать один символ кавычки.
\a Гудок встроенного в систему динамика.
\b Backspace, он же возврат, он же «пробел назад» – удаляет один символ перед курсором.
\f Разрыв страницы.
\n Перенос строки (новая строка).
\r Возврат курсора в начало строки.
\t Горизонтальный отступ слева от начала строки (горизонтальная табуляция).
\v Вертикальный отступ сверху (вертикальная табуляция).
\xhh Шестнадцатеричный код символа (две шестнадцатеричные цифры hh).
\ooo Восьмеричный код символа (три восьмеричные цифры ooo).
\0 Символ Null.
\N

ID (идентификатор) символа в базе данных Юникода, или, проще говоря, его название в таблице Юникода.
\uhhhh Шестнадцатеричный код 16-битного символа Юникода (символ кодируемый двумя байтами).
\Uhhhhhhhh Шестнадцатеричный код 32-битного символа Юникода (символ кодируемый четырьмя байтами).
\other Под other понимается любая другая последовательность символов. Не является экранированной последовательностью (остается без изменений с сохранением в строке символа » \ «).

Примеры

\newline — новая строка

Данный символ позволяет записывать очень длинные «короткие» строки (строки в одинарных кавычках или апострофах) в несколько строк. Как это работает? Просто начните вводить строку, в необходимом месте введите символ » \ » а потом сразу нажмите клавишу Enter и продолжайте ввод строки. Например:

Обратите внимание, что в результирующей строке вообще нет символа » \ «. И не забывайте что пробел тоже является символом, а последовательность \newline не является разделителем:

\\ — обратный слеш

Позволяет указывать в строке необходимое количество обратных слешей, что может пригодиться при работе с файловой системой в Windows или работой с LATEX:

Обратите на то как выполняется непосредственный вывод строк, в котором сохраняются экранированные последовательности и на то как выполняется вывод с помощью функции print() которая выполняет их интерпретацию и заменяет последовательности \\ на \ .

Новичков это немного сбивает с толку, так как они думают, что строка с путем D:\\\\мои документы\\книги\\ является неверной записью пути к директории, хотя это не так, потому что последовательность \\ интерпретируется как одино символ, которому ставится в соответствие один код, в чем легко убедиться:

\’ — апостроф

Последовательность \’ позволяет помещать внутрь строки необходимое количество апострофов:

\» — кавычка

Так же как и \’ позволяет помещать в строку необходимое количество кавычек:

\a — гудок динамика

Последовательность \a заставляет систему издать короткий звуковой гудок, который очень часто используется для предупреждения о чем-либо. Однако, услышите вы этот гудок или нет, как-то зависит от компьютера и операционной системы. Например я сейчас работаю на ноуте под Ubuntu и ничего не слышу, но на стационарном компьютере с Windows 7 все исправно работает. Использовать его или нет решайте сами, но в любом случае, этот символ никогда не выводится на экран:

\b — backspace (пробел назад)

Если вы хоть раз нажимали клавишу Backspace на клавиатуре, то вы уже знаете предназначение этой последовательности – удалять один символ перед курсором:

Если \b находится в конце строки, то удаления не происходит:

Однако, в общем случае все зависит от того сколько символов \b следует подряд друг за другом и что следует за ними:

Данная последовательность используется крайне редко. Но если вы все еще не догадались как она работает, то лучше воспринимайте его не как удаление символов, а как перемещение курсора влево. Например, в строке ‘AAAA\b\b\bC’ мы как бы ничего и не удаляли, на самом деле три символа ‘\b\b\b’ переместили курсор на три позиции влево, на на вторую букву ‘A’ и вместо нее напечатали символ ‘C’ .

Последовательность \b – это эхо из эры механических печатных машинок, у которых не было курсора, а была каретка, которую курсор и имитирует. Сейчас клавиша Backspace ассоциируется с удалением символа, но на самом деле, раньше выполнялось перемещение каретки на один символ влево, т.е. на одном и том же месте бумаги можно было напечатать несколько разных символов.

\f — разрыв страницы

Последовательность \f – указывает в каком месте заканчивается одна страница и начинается другая. Раньше он использовался для управления подачей бумаги в принтерах. Когда принтер встречал этот символ, это означало что ему надо было извлеч страницу и загрузить на печать следующий лист бумаги. Сейчас, он может встретиться (и то не факт, что встретится) разве что в исходных кодах некоторых языков программирования, в которых принято соглашение разбивать код на разделы с помощью этого символа. Например, интерпретатор Python способен учитывать \f при расчете отступов при анализе кода.

Данная последовательность переводит курсор на следующую строку и выполняет отступ, длина которого равна длине предшествоваишей \f части строки:

\n — перенос строки

Последовательность \n до банального проста – это просто перенос следующих за ним символов на следующую строку:

\r — возврат каретки

Последовательность \r возвращает курсор в начало строки, т.е. позволяет печатать одни символы «поверх» других. Например:

Данная последовательность позволяет зделать «полосу загрузки» или осуществлять вывод прогресса решения каких-нибудь задач. Но для этого нужно знать, что функция print() обладает параметром end который по умолчанию установлен в значение ‘\n’ , что заставляет заканчивать каждый вывод переводом на новую строку:

 

Параметр end определяет каким символом должна заканчиваться строка, т.е. мы можем сами задать такой символ (или символы):

Если мы зделаем end = ‘\r’ , то мы сможем печатать строки «поверх» друг друга, но терминал делает это настолько быстро, что мы не успеем ничего заметить. Обычно, загрузка и выполнение каких-то задач сопровождается небольшими задержками, давайте, мы съимитируем такую задержку с помощью функции sleep() модуля time :

\t — горизонтальная табуляция

Так же как и \n последовательность \t крайне проста – она просто делает один отступ (равносильно нажатию клавиши Tab):

\v — вертикальная табуляция

Последовательность \v очень похожа на \f и точно так же родом из тех времен, когда принтером приходилось управлять чуть ли не на прямую. Вот только эта последовательность в отличии от \f , не заставляла его загружать новую страницу, а перемещала его вниз по странице на указанное количество строк.

Но самое любопытное, что от этих раритетов в некоторых областях даже не собираются отказываться — некоторые документы и стандарты до сих пор используют последовательности \v и \f .

\xhh — шестнадцатеричный код символа

Последовательность \xhh позволяет делать запись строк, используя шестнадцатеричный код символов:

\ooo — восьмеричный код символа

Последовательность \ooo позволяет делать запись строк, используя восьмеричный код символов:

\0 — Null

Данная последовательность ведет себя так, словно ее нет. В старые-добрые времена механических принтеров, эта последовательность обозначала простой, т.е. ничего не делать. Сейчас ее можно до сих пор встретить в языке C, в конце символьных строк, причем далее за » \0 » другие цифры следовать не должны, иначе они будут восприниматься как другая экранированная восьмеричная последовательность. Ну а Python этот символ вообще никак не выводит:

Тем не менее этот символ в строке сохраняется и влияет на ее длину.

\N — идентификатор символа Юникода

Позволяет вводить символы в строку используя их название:

\uhhhh — 16-битный символ Юникода

Позволяет вводить символы в строку используя их двухбайтовый шестнадцатеричный код, причем данный способ позволяет вводить только двухбайтовые символы юникода (UTF-16BE):

\Uhhhhhhhh — 32-битный символ Юникода

Позволяет вводить символы в строку используя их четырехбайтовый шестнадцатеричный код, причем данный способ позволяет вводить только четырехбайтовые символы юникода (UTF-32BE):

\other — не экранированная последовательность

Если за символом » \ » следует что-то другое, не перечисленное в данном списке, то это не считается экранированной последовательностью, а обычной строкой в которой на ряду с остальными символами присутствует и символ » \ «:

Но внимательность все же не помешает:

Всегда экранируйте символ » \ » последовательностью » \\ » или используйте литерал неформатированных строк r’aaaa\bbbb’ .

Форматирование текста в Python 3

Строки часто состоят из обычного текста, следовательно, есть много ситуаций, в которых разработчику необходимо иметь возможность изменить внешний вид строки, сделать её более читабельной.

Данное руководство рассматривает несколько способов форматирования строк Python.

Строковые литералы

В чём разница между строковым литералом и значением строки? Строковый литерал – это то, что вы видите в коде программы, включая кавычки. Значение строки – это то, что появляется на экране при вызове функции print() или запуске программы.

К примеру, в программе Hello, World!:

  • Литерал – “Hello, World!”;
  • Значение – Hello, World!

Значение строки появляется в окне терминала при запуске программы Python.

Однако бывают случаи, когда значение строки должно содержать кавычки. При этом нужно форматировать литерал.

Кавычки и апострофы

В Python строку можно заключать как одиночные, так и в двойные кавычки. Потому значение строки взять в кавычки очень просто: можно просто поместить значение в двойные кавычки, а саму строку – взять в одиночные кавычки. Например:

‘8host says, «Hello!»‘

Чтобы использовать в тексте апостроф, возьмите строку в двойные кавычки:

«Jenny’s dress is red.»

Как видите, вставить апостроф или взять цитату в кавычки очень просто: достаточно научиться комбинировать двойные и одиночные кавычки.

Разбиение строки

Вы можете разбить строку на несколько строк, чтобы сделать текст более удобным для чтения. Это позволяет группировать строки в простой для восприятия, упорядоченный текст. К примеру, так вы можете правильно отобразить стих или текст песни.

Для этого используйте тройные одиночные (”’) или тройные двойные кавычки (“””):

»’
This string is on
multiple lines
within three single
quotes on either side.
»’
«»»
This string is on
multiple lines
within three double
quotes on either side.
«»»

Управляющие последовательности

Ещё один способ отредактировать строку – использовать управляющие последовательности.

Все они начинаются с обратного слеша (\), после чего идёт специальный символ.

Последовательность Функция
\ Символ новой строки
\\ Обратный слеш (\)
\’ Апостроф или одинарная кавычка
\” Двойные кавычки
\n Разрыв строки
\t Горизонтальный отступ

Попробуйте использовать управляющую последовательность, чтобы добавить кавычки в строку:

print(«8host says, \»Hello!\»»)
8host says, «Hello!»

Управляющая последовательность \” взяла строку Hello! в двойные кавычки.

Аналогично, вы можете использовать последовательность \’, чтобы добавить апостроф:

print(‘Jenny\’s dress is red.’)
Jenny’s dress is red.

Используя управляющую последовательность, вы можете взять строку в одинарные кавычки, даже если в ней нужен апостроф.

При использовании тройных кавычек вы можете заметить, что в верхней и нижней части при выводе строки остаётся свободное пространство. Чтобы удалить эти пробелы, воспользуйтесь последовательностью \ бежать в верхней и нижней части строки.

«»»\
This multi-line string
has no space at the
top or the bottom
when it prints.\
«»»

Также можно разделить строку на несколько строк с помощью последовательности \n:

print(«This string\nspans multiple\nlines.»)
This string
spans multiple
lines.

Управляющие последовательности можно комбинировать. Попробуйте вывести несколько строк и добавить табуляцию.

print(«1.\tShark\n2.\tShrimp\n10.\tSquid»)
1. Shark
2. Shrimp
3. Squid

Горизонтальный отступ обеспечивает выравнивание внутри второго столбца, благодаря чему текст становится читабельным.

Управляющие последовательности позволяют форматировать строки, которые невозможно или очень сложно отформатировать простым чередованием кавычек. К примеру, как без помощи последовательностей отформатировать строку:

July says, «Is Jenny’s dress red?»

Как отключить управляющие последовательности

Бывают ситуации, когда строка должна отображать символ, входящий в управляющую последовательность: например, в строке должен быть обратный слеш.

Чтобы Python читал строку буквально, не выполняя управляющих последовательностей, используется оператор r (raw string). Чтобы создать «неформатированную» строку, нужно просто добавить r перед кавычками:

print(r» July says,\»Is Jenny’\s dress red?\»»)
July says,\»Is Jenny’\s dress red?\»

Заключение

Теперь вы знакомы с основными методами форматирования строк в Python 3. Это позволит вам сделать строки, отображаемые программой, удобными и простыми для восприятия пользователей.

Python: советы, уловки, хаки (часть 1)

Хотите писать более лаконичный и читаемый код? Вы хотите уместить как можно больше смысла в одно выражение? Считаете, что прочитать о нескольких уловках лучше, чем провести остаток жизни за чтением документации? Вы обратились по адресу. Мы начнем с маленьких уловок, которые вы уже могли встретить, если немного работали с Python. Но я обещаю, что ближе к концу статьи вас ожидает больше безумных вещей.

Содержание

1. Маленькие уловки. Четыре типа кавычек. Правдивость различных объектов. Проверка на вхождение подстроки. Красивый вывод списка. Целочисленное деление и деление с плавающей точкой. Лямбда-функции.
2. Списки. Генераторы списков и выражения-генераторы.

Я старался сделать, чтобы все фрагменты кода запускались без дополнительных изменений. Если хотите, можете скопировать их в оболочку Python и посмотреть, что получится. Обратите внимание, что многие примеры содержат «неправильные» фрагменты, которые закомментированы. Ничто вам не мешает раскомментировать строку и посмотреть, что произойдет.

Небольшое разграничение между true и True в этой статье: когда я говорю, что объект true, это значит, что будучи приведенным к типу boolean, он становится True. Аналогично с false и False.

1 Маленькие уловки
1.1 Четыре типа кавычек

Начнем с того, что вы, возможно, уже знаете. В некоторых языках программирования одинарные и двойные кавычки предназначены для разных вещей. Python позволяет использовать оба варианта (но строка должна начинаться и заканчиваться одним и тем же типом кавычек). В Python также есть еще два типа кавычек: »’ (тройные одинарные) и «»» (тройные двойные). Таким образом, можно использовать несколько уровней кавычек, прежде чем придется заботиться об их экранировании. Например, этот код правильный:

1.2 Правдивость различных объектов

В отличие от некоторых языков программирования, в Python объект считается false, только если он пуст. Это значит, что не нужно проверять длину строки, кортежа или словаря — достаточно проверить его как логическое выражение.

Легко предсказать, что 0 — тоже false, а остальные числа — true.

Например, следующие выражения эквивалентны. В данном случае my_object — строка, но здесь мог оказаться другой тип (с соответствующими изменениями условий блока if).

Итак, нет необходимости проверять длину объекта, если вас интересует только, пуст он или нет.

1.3 Проверка на вхождение подстроки

Это маленькая, довольно очевидная подсказка, но я узнал о ней лишь через год изучения Python. Должно быть, вы знаете, что можно проверить, содержится ли нужный элемент в кортеже, списке, словаре, с помощью конструкции ‘item in list’ или ‘item not in list’. Я не мог представить, что это сработает для строк. Я всегда писал что-то вроде этого:

Этот код довольно неуклюжий. Совершенно так же работает ‘if substring in string’:

Проще и понятней. Может быть, очевидно для 99% людей, но мне хотелось бы узнать об этом раньше, чем я узнал.

1.4 Красивый вывод списка

Обычный формат вывода списка с помощью print не очень удобен. Конечно, становится понятно, что из себя представляет список, но чаще всего пользователь не хочет видеть кавычки вокруг каждого элемента. Есть простое решение, использующее метод join строки:

Метод join преобразовывает список в строку, рассматривая каждый элемент как строку. Разделителем является та строка, для которой был вызван join. Он достаточно умен, чтобы не вставлять разделитель после последнего элемента.

Дополнительный бонус: join работает линейное время. Никогда не создавайте строку складыванием элементов списка в цикле for: это не просто некрасиво, это занимает квадратичное время!

1.5 Целочисленное деление и деление с плавающей точкой

Если вы делите целое число на целое, по умолчанию результат обрезается до целого. Например, 5/2 вернет 2.

Есть два способа это исправить. Первый и самый простой способ заключается в том, чтобы преобразовать одно из чисел к типу float. Для констант достаточно добавить «.0» к одному из чисел: 5.0/2 вернет 2.5. Также вы можете использовать конструкцию float(5)/2.

Второй способ дает более чистый код, но вы должны убедиться, что ваша программа не сломается от этого существенного изменения. После вызова ‘from __future__ import division’ Python всегда будет возвращать в качестве результата деления float. Если вам понадобится целочисленное деление, используйте оператор //: 5//2 всегда возвращает 2.

В одной из следующих версий Python такое поведение станет дефолтным. Если вы хотите, чтобы ваш код оставался совместимым, используйте оператор // для целочисленного деления, даже если вы не используете этот импорт.

1.6 Лямбда-функции

Иногда нужно передать функцию в качестве аргумента или сделать короткую, но сложную операцию несколько раз. Можно определить функцию обычным способом, а можно использовать лямбда-функцию — маленькую функцию, возвращающую результат одного выражения. Следующие два определения полностью идентичны:

Преимущество лямбда-функции в том, что она является выражением и может быть использована внутри другого выражения. Ниже приведен пример, использующий функцию map, которая вызывает функцию для каждого элемента списка и возвращает список результатов. (В следующем пункте я покажу, что map практически бесполезен. Но он дает нам возможность привести хороший пример в одну строку.)

Без лямбда-функций нам пришлось бы определить функцию отдельно. Мы просто сэкономили одну строку кода и одно имя переменной.

2 Списки
2.1 Генераторы списков

Если вы использовали Python достаточно долго, вы должны были хотя бы слышать о понятии «list comprehensions». Это способ уместить цикл for, блок if и присваивание в одну строку.
Другими словами, вы можете отображать (map) и фильтровать списки одним выражением.

2.1.1 Отображение списка

Начнем с простейшего примера. Допустим, нам надо возвести в квадрат все элементы списка. Свежеиспеченный программист на Python может написать код вроде этого:

Мы «отобразили» один список на другой. Это также можно сделать с помощью функции map:

Этот код определенно короче (одна строка вместо трех), но всё еще некрасив. С первого взгляда сложно сказать, что делает функция map (она принимает в качестве аргументов функцию и список и применяет функцию к каждому элементу списка). К тому же мы вынуждены определять функцию, это выглядит довольно беспорядочно. Если бы только существовал более красивый путь… например, генератор списка:

Этот код делает абсолютно то же самое, но он короче, чем первый пример, и понятней, чем второй. Человек без проблем определит, что делает код, для этого даже не обязательно знать Python.

2.1.2 Фильтрация списка

А что, если нас интересует фильтрация списка? Например, требуется удалить элементы, большие или равные 4. (Да, примеры не очень реалистичны. Как бы то ни было. )

Новичок напишет так:

Очень просто, не так ли? Но код занимает 4 строки, содержит два уровня отступов и при этом делает тривиальную вещь. Можно уменьшить размер кода с помощью функции filter:

Аналогично функции map, о которой мы говорили выше, filter сокращает код, но выглядит довольно уродливо. Что, черт возьми, происходит? Как и map, filter получает функцию и список. Если функция от элемента возвращает true, элемент включается в результирующий список. Разумеется, мы можем сделать это через генератор списка:

Снова мы получили более короткий, ясный и понятный код.

2.1.3 Одновременное использование map и filter

Теперь мы можем использовать всю силу генератора списков. Если я вас еще не убедил, что map и filter тратят слишком много вашего времени, надеюсь, теперь вы со мной согласитесь.

Пусть требуется отобразить и отфильтровать список одновременно. Другими словами, я хочу увидеть квадраты элементов списка, меньших 4. Еще раз, неофит напишет так:

Увы, код начал растягиваться вправо. Может, получится упростить его? Попробуем использовать map и filter, но у меня плохое предчувствие…

Раньше map и filter было трудно читать, теперь — невозможно. Очевидно, это не лучшая идея. И снова генератор списков спасает ситуацию:

Получилось немного длиннее, чем предыдущие примеры с генератором списков, но, по моему мнению, вполне читабельно. Определенно лучше, чем цикл for или использование map и filter.

Как вы видите, генератор списков сначала фильтрует, а затем отображает. Если вам обязательно нужно наоборот, получится сложнее. Придется использовать либо вложенные генерации, либо map и filter, либо обычный цикл for, в зависимости от того, что проще. Но это уже выходит за рамки статьи.

2.1.4 Выражения-генераторы

Существует обратная сторона генератора списков: весь список должен находиться в памяти. Это не проблема для маленьких списков, как в предыдущих примерах, и даже на несколько порядков больше. Но в конце концов это становится неэффективным.

Выражения-генераторы (Generator Expressions) появились в Python 2.4. Из всех фишек Python им уделяется, наверно, меньше всего внимания. Отличие их от генераторов списков состоит в том, что они не загружают в память список целиком, а создают ‘generator object’, и в каждый момент загружен только один элемент списка.

Конечно, если вы хотите использовать список для чего-нибудь, это не особо поможет. Но если вы просто передаете его куда-нибудь, где нужен любой итерируемый объект (цикл for, например), стоит использовать функцию генератора.

Выражения-генераторы имеют такой же синтаксис, как генераторы списков, но вместо квадратных скобок используются круглые:

Это более эффективно, чем использование генератора списков.

Итак, имеет смысл использовать выражения-генераторы для списков больших размеров. Если весь список целиком нужен вам для какой-то другой цели, то можно использовать любой из вариантов. Но использовать выражения-генераторы — хорошая привычка, если нет аргументов против этого. Правда, не надейтесь увидеть ускорение работы, если список небольшой.

В качестве финального штриха хочу заметить, что выражения-генераторы достаточно заключить в одни круглые скобки. Например, в случае, если вы вызываете функцию с одним аргументом, можно писать так: some_function(item for item in list).

2.1.5 Заключение

Мне не хочется этого говорить, но мы только прикоснулись к тому, что можно делать с помощью выражений-генераторов и генераторов списков. Здесь можно использовать всю силу for и if, а также оперировать с чем угодно, лишь бы оно было итерируемым объектом.

 

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *