Меню

Python f строки ошибка

Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Identify Invalid Python Syntax

Python is known for its simple syntax. However, when you’re learning Python for the first time or when you’ve come to Python with a solid background in another programming language, you may run into some things that Python doesn’t allow. If you’ve ever received a SyntaxError when trying to run your Python code, then this guide can help you. Throughout this tutorial, you’ll see common examples of invalid syntax in Python and learn how to resolve the issue.

By the end of this tutorial, you’ll be able to:

  • Identify invalid syntax in Python
  • Make sense of SyntaxError tracebacks
  • Resolve invalid syntax or prevent it altogether

Invalid Syntax in Python

When you run your Python code, the interpreter will first parse it to convert it into Python byte code, which it will then execute. The interpreter will find any invalid syntax in Python during this first stage of program execution, also known as the parsing stage. If the interpreter can’t parse your Python code successfully, then this means that you used invalid syntax somewhere in your code. The interpreter will attempt to show you where that error occurred.

When you’re learning Python for the first time, it can be frustrating to get a SyntaxError. Python will attempt to help you determine where the invalid syntax is in your code, but the traceback it provides can be a little confusing. Sometimes, the code it points to is perfectly fine.

You can’t handle invalid syntax in Python like other exceptions. Even if you tried to wrap a try and except block around code with invalid syntax, you’d still see the interpreter raise a SyntaxError.

SyntaxError Exception and Traceback

When the interpreter encounters invalid syntax in Python code, it will raise a SyntaxError exception and provide a traceback with some helpful information to help you debug the error. Here’s some code that contains invalid syntax in Python:

 1# theofficefacts.py
 2ages = {
 3    'pam': 24,
 4    'jim': 24
 5    'michael': 43
 6}
 7print(f'Michael is {ages["michael"]} years old.')

You can see the invalid syntax in the dictionary literal on line 4. The second entry, 'jim', is missing a comma. If you tried to run this code as-is, then you’d get the following traceback:

$ python theofficefacts.py
File "theofficefacts.py", line 5
    'michael': 43
            ^
SyntaxError: invalid syntax

Note that the traceback message locates the error in line 5, not line 4. The Python interpreter is attempting to point out where the invalid syntax is. However, it can only really point to where it first noticed a problem. When you get a SyntaxError traceback and the code that the traceback is pointing to looks fine, then you’ll want to start moving backward through the code until you can determine what’s wrong.

In the example above, there isn’t a problem with leaving out a comma, depending on what comes after it. For example, there’s no problem with a missing comma after 'michael' in line 5. But once the interpreter encounters something that doesn’t make sense, it can only point you to the first thing it found that it couldn’t understand.

There are a few elements of a SyntaxError traceback that can help you determine where the invalid syntax is in your code:

  • The file name where the invalid syntax was encountered
  • The line number and reproduced line of code where the issue was encountered
  • A caret (^) on the line below the reproduced code, which shows you the point in the code that has a problem
  • The error message that comes after the exception type SyntaxError, which can provide information to help you determine the problem

In the example above, the file name given was theofficefacts.py, the line number was 5, and the caret pointed to the closing quote of the dictionary key michael. The SyntaxError traceback might not point to the real problem, but it will point to the first place where the interpreter couldn’t make sense of the syntax.

There are two other exceptions that you might see Python raise. These are equivalent to SyntaxError but have different names:

  1. IndentationError
  2. TabError

These exceptions both inherit from the SyntaxError class, but they’re special cases where indentation is concerned. An IndentationError is raised when the indentation levels of your code don’t match up. A TabError is raised when your code uses both tabs and spaces in the same file. You’ll take a closer look at these exceptions in a later section.

Common Syntax Problems

When you encounter a SyntaxError for the first time, it’s helpful to know why there was a problem and what you might do to fix the invalid syntax in your Python code. In the sections below, you’ll see some of the more common reasons that a SyntaxError might be raised and how you can fix them.

Misusing the Assignment Operator (=)

There are several cases in Python where you’re not able to make assignments to objects. Some examples are assigning to literals and function calls. In the code block below, you can see a few examples that attempt to do this and the resulting SyntaxError tracebacks:

>>>

>>> len('hello') = 5
  File "<stdin>", line 1
SyntaxError: can't assign to function call

>>> 'foo' = 1
  File "<stdin>", line 1
SyntaxError: can't assign to literal

>>> 1 = 'foo'
  File "<stdin>", line 1
SyntaxError: can't assign to literal

The first example tries to assign the value 5 to the len() call. The SyntaxError message is very helpful in this case. It tells you that you can’t assign a value to a function call.

The second and third examples try to assign a string and an integer to literals. The same rule is true for other literal values. Once again, the traceback messages indicate that the problem occurs when you attempt to assign a value to a literal.

It’s likely that your intent isn’t to assign a value to a literal or a function call. For instance, this can occur if you accidentally leave off the extra equals sign (=), which would turn the assignment into a comparison. A comparison, as you can see below, would be valid:

>>>

>>> len('hello') == 5
True

Most of the time, when Python tells you that you’re making an assignment to something that can’t be assigned to, you first might want to check to make sure that the statement shouldn’t be a Boolean expression instead. You may also run into this issue when you’re trying to assign a value to a Python keyword, which you’ll cover in the next section.

Misspelling, Missing, or Misusing Python Keywords

Python keywords are a set of protected words that have special meaning in Python. These are words you can’t use as identifiers, variables, or function names in your code. They’re a part of the language and can only be used in the context that Python allows.

There are three common ways that you can mistakenly use keywords:

  1. Misspelling a keyword
  2. Missing a keyword
  3. Misusing a keyword

If you misspell a keyword in your Python code, then you’ll get a SyntaxError. For example, here’s what happens if you spell the keyword for incorrectly:

>>>

>>> fro i in range(10):
  File "<stdin>", line 1
    fro i in range(10):
        ^
SyntaxError: invalid syntax

The message reads SyntaxError: invalid syntax, but that’s not very helpful. The traceback points to the first place where Python could detect that something was wrong. To fix this sort of error, make sure that all of your Python keywords are spelled correctly.

Another common issue with keywords is when you miss them altogether:

>>>

>>> for i range(10):
  File "<stdin>", line 1
    for i range(10):
              ^
SyntaxError: invalid syntax

Once again, the exception message isn’t that helpful, but the traceback does attempt to point you in the right direction. If you move back from the caret, then you can see that the in keyword is missing from the for loop syntax.

You can also misuse a protected Python keyword. Remember, keywords are only allowed to be used in specific situations. If you use them incorrectly, then you’ll have invalid syntax in your Python code. A common example of this is the use of continue or break outside of a loop. This can easily happen during development when you’re implementing things and happen to move logic outside of a loop:

>>>

>>> names = ['pam', 'jim', 'michael']
>>> if 'jim' in names:
...     print('jim found')
...     break
...
  File "<stdin>", line 3
SyntaxError: 'break' outside loop

>>> if 'jim' in names:
...     print('jim found')
...     continue
...
  File "<stdin>", line 3
SyntaxError: 'continue' not properly in loop

Here, Python does a great job of telling you exactly what’s wrong. The messages "'break' outside loop" and "'continue' not properly in loop" help you figure out exactly what to do. If this code were in a file, then Python would also have the caret pointing right to the misused keyword.

Another example is if you attempt to assign a Python keyword to a variable or use a keyword to define a function:

>>>

>>> pass = True
  File "<stdin>", line 1
    pass = True
         ^
SyntaxError: invalid syntax

>>> def pass():
  File "<stdin>", line 1
    def pass():
           ^
SyntaxError: invalid syntax

When you attempt to assign a value to pass, or when you attempt to define a new function called pass, you’ll get a SyntaxError and see the "invalid syntax" message again.

It might be a little harder to solve this type of invalid syntax in Python code because the code looks fine from the outside. If your code looks good, but you’re still getting a SyntaxError, then you might consider checking the variable name or function name you want to use against the keyword list for the version of Python that you’re using.

The list of protected keywords has changed with each new version of Python. For example, in Python 3.6 you could use await as a variable name or function name, but as of Python 3.7, that word has been added to the keyword list. Now, if you try to use await as a variable or function name, this will cause a SyntaxError if your code is for Python 3.7 or later.

Another example of this is print, which differs in Python 2 vs Python 3:

Version print Type Takes A Value
Python 2 keyword no
Python 3 built-in function yes

print is a keyword in Python 2, so you can’t assign a value to it. In Python 3, however, it’s a built-in function that can be assigned values.

You can run the following code to see the list of keywords in whatever version of Python you’re running:

import keyword
print(keyword.kwlist)

keyword also provides the useful keyword.iskeyword(). If you just need a quick way to check the pass variable, then you can use the following one-liner:

>>>

>>> import keyword; keyword.iskeyword('pass')
True

This code will tell you quickly if the identifier that you’re trying to use is a keyword or not.

Missing Parentheses, Brackets, and Quotes

Often, the cause of invalid syntax in Python code is a missed or mismatched closing parenthesis, bracket, or quote. These can be hard to spot in very long lines of nested parentheses or longer multi-line blocks. You can spot mismatched or missing quotes with the help of Python’s tracebacks:

>>>

>>> message = 'don't'
  File "<stdin>", line 1
    message = 'don't'
                   ^
SyntaxError: invalid syntax

Here, the traceback points to the invalid code where there’s a t' after a closing single quote. To fix this, you can make one of two changes:

  1. Escape the single quote with a backslash ('don't')
  2. Surround the entire string in double-quotes instead ("don't")

Another common mistake is to forget to close string. With both double-quoted and single-quoted strings, the situation and traceback are the same:

>>>

>>> message = "This is an unclosed string
  File "<stdin>", line 1
    message = "This is an unclosed string
                                        ^
SyntaxError: EOL while scanning string literal

This time, the caret in the traceback points right to the problem code. The SyntaxError message, "EOL while scanning string literal", is a little more specific and helpful in determining the problem. This means that the Python interpreter got to the end of a line (EOL) before an open string was closed. To fix this, close the string with a quote that matches the one you used to start it. In this case, that would be a double quote (").

Quotes missing from statements inside an f-string can also lead to invalid syntax in Python:

 1# theofficefacts.py
 2ages = {
 3    'pam': 24,
 4    'jim': 24,
 5    'michael': 43
 6}
 7print(f'Michael is {ages["michael]} years old.')

Here, the reference to the ages dictionary inside the printed f-string is missing the closing double quote from the key reference. The resulting traceback is as follows:

$ python theofficefacts.py
  File "theofficefacts.py", line 7
    print(f'Michael is {ages["michael]} years old.')
         ^
SyntaxError: f-string: unterminated string

Python identifies the problem and tells you that it exists inside the f-string. The message "unterminated string" also indicates what the problem is. The caret in this case only points to the beginning of the f-string.

This might not be as helpful as when the caret points to the problem area of the f-string, but it does narrow down where you need to look. There’s an unterminated string somewhere inside that f-string. You just have to find out where. To fix this problem, make sure that all internal f-string quotes and brackets are present.

The situation is mostly the same for missing parentheses and brackets. If you leave out the closing square bracket from a list, for example, then Python will spot that and point it out. There are a few variations of this, however. The first is to leave the closing bracket off of the list:

# missing.py
def foo():
    return [1, 2, 3

print(foo())

When you run this code, you’ll be told that there’s a problem with the call to print():

$ python missing.py
  File "missing.py", line 5
    print(foo())
        ^
SyntaxError: invalid syntax

What’s happening here is that Python thinks the list contains three elements: 1, 2, and 3 print(foo()). Python uses whitespace to group things logically, and because there’s no comma or bracket separating 3 from print(foo()), Python lumps them together as the third element of the list.

Another variation is to add a trailing comma after the last element in the list while still leaving off the closing square bracket:

# missing.py
def foo():
    return [1, 2, 3,

print(foo())

Now you get a different traceback:

$ python missing.py
  File "missing.py", line 6

                ^
SyntaxError: unexpected EOF while parsing

In the previous example, 3 and print(foo()) were lumped together as one element, but here you see a comma separating the two. Now, the call to print(foo()) gets added as the fourth element of the list, and Python reaches the end of the file without the closing bracket. The traceback tells you that Python got to the end of the file (EOF), but it was expecting something else.

In this example, Python was expecting a closing bracket (]), but the repeated line and caret are not very helpful. Missing parentheses and brackets are tough for Python to identify. Sometimes the only thing you can do is start from the caret and move backward until you can identify what’s missing or wrong.

Mistaking Dictionary Syntax

You saw earlier that you could get a SyntaxError if you leave the comma off of a dictionary element. Another form of invalid syntax with Python dictionaries is the use of the equals sign (=) to separate keys and values, instead of the colon:

>>>

>>> ages = {'pam'=24}
  File "<stdin>", line 1
    ages = {'pam'=24}
                 ^
SyntaxError: invalid syntax

Once again, this error message is not very helpful. The repeated line and caret, however, are very helpful! They’re pointing right to the problem character.

This type of issue is common if you confuse Python syntax with that of other programming languages. You’ll also see this if you confuse the act of defining a dictionary with a dict() call. To fix this, you could replace the equals sign with a colon. You can also switch to using dict():

>>>

>>> ages = dict(pam=24)
>>> ages
{'pam': 24}

You can use dict() to define the dictionary if that syntax is more helpful.

Using the Wrong Indentation

There are two sub-classes of SyntaxError that deal with indentation issues specifically:

  1. IndentationError
  2. TabError

While other programming languages use curly braces to denote blocks of code, Python uses whitespace. That means that Python expects the whitespace in your code to behave predictably. It will raise an IndentationError if there’s a line in a code block that has the wrong number of spaces:

 1# indentation.py
 2def foo():
 3    for i in range(10):
 4        print(i)
 5  print('done')
 6
 7foo()

This might be tough to see, but line 5 is only indented 2 spaces. It should be in line with the for loop statement, which is 4 spaces over. Thankfully, Python can spot this easily and will quickly tell you what the issue is.

There’s also a bit of ambiguity here, though. Is the print('done') line intended to be after the for loop or inside the for loop block? When you run the above code, you’ll see the following error:

$ python indentation.py
  File "indentation.py", line 5
    print('done')
                ^
IndentationError: unindent does not match any outer indentation level

Even though the traceback looks a lot like the SyntaxError traceback, it’s actually an IndentationError. The error message is also very helpful. It tells you that the indentation level of the line doesn’t match any other indentation level. In other words, print('done') is indented 2 spaces, but Python can’t find any other line of code that matches this level of indentation. You can fix this quickly by making sure the code lines up with the expected indentation level.

The other type of SyntaxError is the TabError, which you’ll see whenever there’s a line that contains either tabs or spaces for its indentation, while the rest of the file contains the other. This might go hidden until Python points it out to you!

If your tab size is the same width as the number of spaces in each indentation level, then it might look like all the lines are at the same level. However, if one line is indented using spaces and the other is indented with tabs, then Python will point this out as a problem:

 1# indentation.py
 2def foo():
 3    for i in range(10):
 4        print(i)
 5    print('done')
 6
 7foo()

Here, line 5 is indented with a tab instead of 4 spaces. This code block could look perfectly fine to you, or it could look completely wrong, depending on your system settings.

Python, however, will notice the issue immediately. But before you run the code to see what Python will tell you is wrong, it might be helpful for you to see an example of what the code looks like under different tab width settings:

$ tabs 4 # Sets the shell tab width to 4 spaces
$ cat -n indentation.py
     1   # indentation.py
     2   def foo():
     3       for i in range(10)
     4           print(i)
     5       print('done')
     6   
     7   foo()

$ tabs 8 # Sets the shell tab width to 8 spaces (standard)
$ cat -n indentation.py
     1   # indentation.py
     2   def foo():
     3       for i in range(10)
     4           print(i)
     5           print('done')
     6   
     7   foo()

$ tabs 3 # Sets the shell tab width to 3 spaces
$ cat -n indentation.py
     1   # indentation.py
     2   def foo():
     3       for i in range(10)
     4           print(i)
     5      print('done')
     6   
     7   foo()

Notice the difference in display between the three examples above. Most of the code uses 4 spaces for each indentation level, but line 5 uses a single tab in all three examples. The width of the tab changes, based on the tab width setting:

  • If the tab width is 4, then the print statement will look like it’s outside the for loop. The console will print 'done' at the end of the loop.
  • If the tab width is 8, which is standard for a lot of systems, then the print statement will look like it’s inside the for loop. The console will print 'done' after each number.
  • If the tab width is 3, then the print statement looks out of place. In this case, line 5 doesn’t match up with any indentation level.

When you run the code, you’ll get the following error and traceback:

$ python indentation.py
  File "indentation.py", line 5
    print('done')
                ^
TabError: inconsistent use of tabs and spaces in indentation

Notice the TabError instead of the usual SyntaxError. Python points out the problem line and gives you a helpful error message. It tells you clearly that there’s a mixture of tabs and spaces used for indentation in the same file.

The solution to this is to make all lines in the same Python code file use either tabs or spaces, but not both. For the code blocks above, the fix would be to remove the tab and replace it with 4 spaces, which will print 'done' after the for loop has finished.

Defining and Calling Functions

You might run into invalid syntax in Python when you’re defining or calling functions. For example, you’ll see a SyntaxError if you use a semicolon instead of a colon at the end of a function definition:

>>>

>>> def fun();
  File "<stdin>", line 1
    def fun();
             ^
SyntaxError: invalid syntax

The traceback here is very helpful, with the caret pointing right to the problem character. You can clear up this invalid syntax in Python by switching out the semicolon for a colon.

In addition, keyword arguments in both function definitions and function calls need to be in the right order. Keyword arguments always come after positional arguments. Failure to use this ordering will lead to a SyntaxError:

>>>

>>> def fun(a, b):
...     print(a, b)
...
>>> fun(a=1, 2)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument

Here, once again, the error message is very helpful in telling you exactly what is wrong with the line.

Changing Python Versions

Sometimes, code that works perfectly fine in one version of Python breaks in a newer version. This is due to official changes in language syntax. The most well-known example of this is the print statement, which went from a keyword in Python 2 to a built-in function in Python 3:

>>>

>>> # Valid Python 2 syntax that fails in Python 3
>>> print 'hello'
  File "<stdin>", line 1
    print 'hello'
                ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print('hello')?

This is one of the examples where the error message provided with the SyntaxError shines! Not only does it tell you that you’re missing parenthesis in the print call, but it also provides the correct code to help you fix the statement.

Another problem you might encounter is when you’re reading or learning about syntax that’s valid syntax in a newer version of Python, but isn’t valid in the version you’re writing in. An example of this is the f-string syntax, which doesn’t exist in Python versions before 3.6:

>>>

>>> # Any version of python before 3.6 including 2.7
>>> w ='world'
>>> print(f'hello, {w}')
  File "<stdin>", line 1
    print(f'hello, {w}')
                      ^
SyntaxError: invalid syntax

In versions of Python before 3.6, the interpreter doesn’t know anything about the f-string syntax and will just provide a generic "invalid syntax" message. The problem, in this case, is that the code looks perfectly fine, but it was run with an older version of Python. When in doubt, double-check which version of Python you’re running!

Python syntax is continuing to evolve, and there are some cool new features introduced in Python 3.8:

  • Walrus operator (assignment expressions)
  • F-string syntax for debugging
  • Positional-only arguments

If you want to try out some of these new features, then you need to make sure you’re working in a Python 3.8 environment. Otherwise, you’ll get a SyntaxError.

Python 3.8 also provides the new SyntaxWarning. You’ll see this warning in situations where the syntax is valid but still looks suspicious. An example of this would be if you were missing a comma between two tuples in a list. This would be valid syntax in Python versions before 3.8, but the code would raise a TypeError because a tuple is not callable:

>>>

>>> [(1,2)(2,3)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object is not callable

This TypeError means that you can’t call a tuple like a function, which is what the Python interpreter thinks you’re doing.

In Python 3.8, this code still raises the TypeError, but now you’ll also see a SyntaxWarning that indicates how you can go about fixing the problem:

>>>

>>> [(1,2)(2,3)]
<stdin>:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?
Traceback (most recent call last):   
  File "<stdin>", line 1, in <module>    
TypeError: 'tuple' object is not callable

The helpful message accompanying the new SyntaxWarning even provides a hint ("perhaps you missed a comma?") to point you in the right direction!

Conclusion

In this tutorial, you’ve seen what information the SyntaxError traceback gives you. You’ve also seen many common examples of invalid syntax in Python and what the solutions are to those problems. Not only will this speed up your workflow, but it will also make you a more helpful code reviewer!

When you’re writing code, try to use an IDE that understands Python syntax and provides feedback. If you put many of the invalid Python code examples from this tutorial into a good IDE, then they should highlight the problem lines before you even get to execute your code.

Getting a SyntaxError while you’re learning Python can be frustrating, but now you know how to understand traceback messages and what forms of invalid syntax in Python you might come up against. The next time you get a SyntaxError, you’ll be better equipped to fix the problem quickly!

Watch Now This tutorial has a related video course created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Identify Invalid Python Syntax

Python известен своим простым синтаксисом. Однако, когда вы изучаете Python в первый раз или когда вы попали на Python с большим опытом работы на другом языке программирования, вы можете столкнуться с некоторыми вещами, которые Python не позволяет. Если вы когда-либо получали + SyntaxError + при попытке запустить код Python, то это руководство может вам помочь. В этом руководстве вы увидите общие примеры неправильного синтаксиса в Python и узнаете, как решить эту проблему.

Неверный синтаксис в Python

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

Когда вы изучаете Python в первый раз, может быть неприятно получить + SyntaxError +. Python попытается помочь вам определить, где в вашем коде указан неверный синтаксис, но предоставляемый им traceback может немного сбить с толку. Иногда код, на который он указывает, вполне подходит.

*Примечание:* Если ваш код *синтаксически* правильный, то вы можете получить другие исключения, которые не являются `+ SyntaxError +`. Чтобы узнать больше о других исключениях Python и о том, как их обрабатывать, ознакомьтесь с https://realpython.com/python-exceptions/[Python Exceptions: Введение].

Вы не можете обрабатывать неправильный синтаксис в Python, как и другие исключения. Даже если вы попытаетесь обернуть блок + try + и + кроме + вокруг кода с неверным синтаксисом, вы все равно увидите, что интерпретатор вызовет + SyntaxError +.

+ SyntaxError + Исключение и трассировка

Когда интерпретатор обнаруживает неверный синтаксис в коде Python, он вызовет исключение + SyntaxError + и предоставит трассировку с некоторой полезной информацией, которая поможет вам отладить ошибку. Вот некоторый код, который содержит недопустимый синтаксис в Python:

 1 # theofficefacts.py
 2 ages = {
 3     'pam': 24,
 4     'jim': 24
 5     'michael': 43
 6 }
 7 print(f'Michael is {ages["michael"]} years old.')

Вы можете увидеть недопустимый синтаксис в литерале словаря в строке 4. Во второй записи + 'jim' + пропущена запятая. Если вы попытаетесь запустить этот код как есть, вы получите следующую трассировку:

$ python theofficefacts.py
File "theofficefacts.py", line 5
    'michael': 43
            ^
SyntaxError: invalid syntax

Обратите внимание, что сообщение трассировки обнаруживает ошибку в строке 5, а не в строке 4. Интерпретатор Python пытается указать, где находится неправильный синтаксис. Тем не менее, он может только указать, где он впервые заметил проблему. Когда вы получите трассировку + SyntaxError + и код, на который указывает трассировка, выглядит нормально, тогда вы захотите начать движение назад по коду, пока не сможете определить, что не так.

В приведенном выше примере нет проблемы с запятой, в зависимости от того, что следует после нее. Например, нет проблемы с отсутствующей запятой после + 'michael' + в строке 5. Но как только переводчик сталкивается с чем-то, что не имеет смысла, он может лишь указать вам на первое, что он обнаружил, что он не может понять.

*Примечание:* В этом руководстве предполагается, что вы знакомы с основами *tracebacks* в Python. Чтобы узнать больше о трассировке Python и о том, как их читать, ознакомьтесь с https://realpython.com/python-traceback/[Understanding Python Traceback].

Существует несколько элементов трассировки + SyntaxError +, которые могут помочь вам определить, где в вашем коде содержится неверный синтаксис:

  • Имя файла , где встречается неверный синтаксис

  • Номер строки и воспроизводимая строка кода, где возникла проблема

  • Знак (+ ^ +) в строке ниже воспроизводимого кода, который показывает точку в коде, которая имеет проблему

  • Сообщение об ошибке , которое следует за типом исключения + SyntaxError +, которое может предоставить информацию, которая поможет вам определить проблему

В приведенном выше примере имя файла было + theofficefacts.py +, номер строки был 5, а каретка указывала на закрывающую кавычку из словарного ключа + michael +. Трассировка + SyntaxError + может не указывать на реальную проблему, но она будет указывать на первое место, где интерпретатор не может понять синтаксис.

Есть два других исключения, которые вы можете увидеть в Python. Они эквивалентны + SyntaxError +, но имеют разные имена:

  1. + + IndentationError

  2. + + TabError

Оба эти исключения наследуются от класса + SyntaxError +, но это особые случаи, когда речь идет об отступе. + IndentationError + возникает, когда уровни отступа вашего кода не совпадают. + TabError + возникает, когда ваш код использует и табуляцию, и пробелы в одном файле. Вы познакомитесь с этими исключениями более подробно в следующем разделе.

Общие проблемы с синтаксисом

Когда вы впервые сталкиваетесь с + SyntaxError +, полезно знать, почему возникла проблема и что вы можете сделать, чтобы исправить неверный синтаксис в вашем коде Python. В следующих разделах вы увидите некоторые из наиболее распространенных причин, по которым может быть вызвано «+ SyntaxError +», и способы их устранения.

Неправильное использование оператора присваивания (+ = +)

В Python есть несколько случаев, когда вы не можете назначать объекты. Некоторые примеры присваивают литералам и вызовам функций. В приведенном ниже блоке кода вы можете увидеть несколько примеров, которые пытаются это сделать, и получающиеся в результате трассировки + SyntaxError +:

>>>

>>> len('hello') = 5
  File "<stdin>", line 1
SyntaxError: can't assign to function call

>>> 'foo' = 1
  File "<stdin>", line 1
SyntaxError: can't assign to literal

>>> 1 = 'foo'
  File "<stdin>", line 1
SyntaxError: can't assign to literal

Первый пример пытается присвоить значение + 5 + вызову + len () +. Сообщение + SyntaxError + очень полезно в этом случае. Он говорит вам, что вы не можете присвоить значение вызову функции.

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

*Примечание:* В приведенных выше примерах отсутствует повторяющаяся строка кода и каретка (`+ ^ +`), указывающая на проблему в трассировке. Исключение и обратная трассировка, которые вы видите, будут другими, когда вы находитесь в REPL и пытаетесь выполнить этот код из файла. Если бы этот код был в файле, то вы бы получили повторяющуюся строку кода и указали на проблему, как вы видели в других случаях в этом руководстве.

Вероятно, ваше намерение не состоит в том, чтобы присвоить значение литералу или вызову функции. Например, это может произойти, если вы случайно пропустите дополнительный знак равенства (+ = +), что превратит назначение в сравнение. Сравнение, как вы можете видеть ниже, будет правильным:

>>>

>>> len('hello') == 5
True

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

Неправильное написание, отсутствие или неправильное использование ключевых слов Python

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

Существует три распространенных способа ошибочного использования ключевых слов:

  1. Неправильное написание ключевое слово

  2. Отсутствует ключевое слово

  3. Неправильное использование ключевого слова

Если вы неправильно написали ключевое слово в своем коде Python, вы получите + SyntaxError +. Например, вот что происходит, если вы пишете ключевое слово + for + неправильно:

>>>

>>> fro i in range(10):
  File "<stdin>", line 1
    fro i in range(10):
        ^
SyntaxError: invalid syntax

Сообщение читается как + SyntaxError: неверный синтаксис +, но это не очень полезно. Трассировка указывает на первое место, где Python может обнаружить, что что-то не так. Чтобы исправить эту ошибку, убедитесь, что все ваши ключевые слова Python написаны правильно.

Другая распространенная проблема с ключевыми словами — это когда вы вообще их пропускаете:

>>>

>>> for i range(10):
  File "<stdin>", line 1
    for i range(10):
              ^
SyntaxError: invalid syntax

Еще раз, сообщение об исключении не очень полезно, но трассировка действительно пытается указать вам правильное направление. Если вы отойдете от каретки, то увидите, что ключевое слово + in + отсутствует в синтаксисе цикла + for +.

Вы также можете неправильно использовать защищенное ключевое слово Python. Помните, что ключевые слова разрешено использовать только в определенных ситуациях. Если вы используете их неправильно, у вас будет неправильный синтаксис в коде Python. Типичным примером этого является использование https://realpython.com/python-for-loop/#the-break-and-continue-statements [+ continue + или + break +] вне цикла. Это может легко произойти во время разработки, когда вы реализуете вещи и когда-то перемещаете логику за пределы цикла:

>>>

>>> names = ['pam', 'jim', 'michael']
>>> if 'jim' in names:
...     print('jim found')
...     break
...
  File "<stdin>", line 3
SyntaxError: 'break' outside loop

>>> if 'jim' in names:
...     print('jim found')
...     continue
...
  File "<stdin>", line 3
SyntaxError: 'continue' not properly in loop

Здесь Python отлично говорит, что именно не так. Сообщения " 'break' вне цикла " и " 'continue' не в цикле должным образом " помогут вам точно определить, что делать. Если бы этот код был в файле, то Python также имел бы курсор, указывающий прямо на неправильно использованное ключевое слово.

Другой пример — если вы пытаетесь назначить ключевое слово Python переменной или использовать ключевое слово для определения функции:

>>>

>>> pass = True
  File "<stdin>", line 1
    pass = True
         ^
SyntaxError: invalid syntax

>>> def pass():
  File "<stdin>", line 1
    def pass():
           ^
SyntaxError: invalid syntax

Когда вы пытаетесь присвоить значение + pass +, или когда вы пытаетесь определить новую функцию с именем + pass +, вы получите ` + SyntaxError + и снова увидеть сообщение + «неверный синтаксис» + `.

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

Список защищенных ключевых слов менялся с каждой новой версией Python. Например, в Python 3.6 вы можете использовать + await + в качестве имени переменной или имени функции, но в Python 3.7 это слово было добавлено в список ключевых слов. Теперь, если вы попытаетесь использовать + await + в качестве имени переменной или функции, это вызовет + SyntaxError +, если ваш код для Python 3.7 или более поздней версии.

Другим примером этого является + print +, который отличается в Python 2 от Python 3:

Version print Type Takes A Value

Python 2

keyword

no

Python 3

built-in function

yes

+ print + — это ключевое слово в Python 2, поэтому вы не можете присвоить ему значение. Однако в Python 3 это встроенная функция, которой можно присваивать значения.

Вы можете запустить следующий код, чтобы увидеть список ключевых слов в любой версии Python, которую вы используете:

import keyword
print(keyword.kwlist)

+ keyword + также предоставляет полезную + keyword.iskeyword () +. Если вам просто нужен быстрый способ проверить переменную + pass +, то вы можете использовать следующую однострочную строку:

>>>

>>> import keyword; keyword.iskeyword('pass')
True

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

Отсутствующие скобки, скобки и цитаты

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

>>>

>>> message = 'don't'
  File "<stdin>", line 1
    message = 'don't'
                   ^
SyntaxError: invalid syntax

Здесь трассировка указывает на неверный код, где после закрывающей одинарной кавычки стоит + t '+. Чтобы это исправить, вы можете сделать одно из двух изменений:

  1. Escape одиночная кавычка с обратной косой чертой (+ 'don ' t '+)

  2. Окружить всю строку в двойных кавычках (" не ")

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

>>>

>>> message = "This is an unclosed string
  File "<stdin>", line 1
    message = "This is an unclosed string
                                        ^
SyntaxError: EOL while scanning string literal

На этот раз каретка в трассировке указывает прямо на код проблемы. Сообщение + SyntaxError +, " EOL при сканировании строкового литерала ", немного более конкретно и полезно при определении проблемы. Это означает, что интерпретатор Python дошел до конца строки (EOL) до закрытия открытой строки. Чтобы это исправить, закройте строку с кавычкой, которая совпадает с той, которую вы использовали для ее запуска. В этом случае это будет двойная кавычка (`+» + `).

Кавычки, отсутствующие в инструкциях внутри f-string, также могут привести к неверному синтаксису в Python:

 1 # theofficefacts.py
 2 ages = {
 3     'pam': 24,
 4     'jim': 24,
 5     'michael': 43
 6 }
 7 print(f'Michael is {ages["michael]} years old.')

Здесь, ссылка на словарь + ages + внутри напечатанной f-строки пропускает закрывающую двойную кавычку из ссылки на ключ. Итоговая трассировка выглядит следующим образом:

$ python theofficefacts.py
  File "theofficefacts.py", line 7
    print(f'Michael is {ages["michael]} years old.')
         ^
SyntaxError: f-string: unterminated string

Python идентифицирует проблему и сообщает, что она существует внутри f-строки. Сообщение " неопределенная строка " также указывает на проблему. Каретка в этом случае указывает только на начало струны.

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

Ситуация в основном отсутствует в скобках и скобках. Например, если вы исключите закрывающую квадратную скобку из списка, Python обнаружит это и укажет на это. Однако есть несколько вариантов этого. Первый — оставить закрывающую скобку вне списка:

# missing.py
def foo():
    return [1, 2, 3

print(foo())

Когда вы запустите этот код, вам скажут, что есть проблема с вызовом + print () +:

$ python missing.py
  File "missing.py", line 5
    print(foo())
        ^
SyntaxError: invalid syntax

Здесь происходит то, что Python думает, что список содержит три элемента: + 1 +, + 2 + и +3 print (foo ()) +. Python использует whitespace для логической группировки вещей, и потому что нет запятой или скобки, отделяющей + 3 + от `+ print (foo ()) + `, Python объединяет их вместе как третий элемент списка.

Еще один вариант — добавить запятую после последнего элемента в списке, оставляя при этом закрывающую квадратную скобку:

# missing.py
def foo():
    return [1, 2, 3,

print(foo())

Теперь вы получаете другую трассировку:

$ python missing.py
  File "missing.py", line 6

                ^
SyntaxError: unexpected EOF while parsing

В предыдущем примере + 3 + и + print (foo ()) + были объединены в один элемент, но здесь вы видите запятую, разделяющую два. Теперь вызов + print (foo ()) + добавляется в качестве четвертого элемента списка, и Python достигает конца файла без закрывающей скобки. В трассировке говорится, что Python дошел до конца файла (EOF), но ожидал чего-то другого.

В этом примере Python ожидал закрывающую скобку (+] +), но повторяющаяся строка и каретка не очень помогают. Отсутствующие круглые скобки и скобки сложно определить Python. Иногда единственное, что вы можете сделать, это начать с каретки и двигаться назад, пока вы не сможете определить, чего не хватает или что нет.

Ошибочный синтаксис словаря

Вы видели ссылку: # syntaxerror-exception-and-traceback [ранее], чтобы вы могли получить + SyntaxError +, если не указывать запятую в словарном элементе. Другая форма недопустимого синтаксиса в словарях Python — это использование знака равенства (+ = +) для разделения ключей и значений вместо двоеточия:

>>>

>>> ages = {'pam'=24}
  File "<stdin>", line 1
    ages = {'pam'=24}
                 ^
SyntaxError: invalid syntax

Еще раз, это сообщение об ошибке не очень полезно. Повторная линия и каретка, однако, очень полезны! Они указывают прямо на характер проблемы.

Этот тип проблемы распространен, если вы путаете синтаксис Python с синтаксисом других языков программирования. Вы также увидите это, если перепутаете определение словаря с вызовом + dict () +. Чтобы это исправить, вы можете заменить знак равенства двоеточием. Вы также можете переключиться на использование + dict () +:

>>>

>>> ages = dict(pam=24)
>>> ages
{'pam': 24}

Вы можете использовать + dict () + для определения словаря, если этот синтаксис более полезен.

Использование неправильного отступа

Существует два подкласса + SyntaxError +, которые конкретно занимаются проблемами отступов:

  1. + + IndentationError

  2. + + TabError

В то время как другие языки программирования используют фигурные скобки для обозначения блоков кода, Python использует whitespace. Это означает, что Python ожидает, что пробелы в вашем коде будут вести себя предсказуемо. Он вызовет + IndentationError + , если в блоке кода есть строка с неправильным количеством пробелов:

 1 # indentation.py
 2 def foo():
 3     for i in range(10):
 4         print(i)
 5   print('done')
 6
 7 foo()

Это может быть сложно увидеть, но в строке 5 есть только два пробела с отступом. Он должен соответствовать выражению цикла + for +, которое на 4 пробела больше. К счастью, Python может легко определить это и быстро расскажет вам, в чем проблема.

Здесь также есть некоторая двусмысленность. Является ли строка + print ('done') + after циклом + for + или inside блоком цикла + for +? Когда вы запустите приведенный выше код, вы увидите следующую ошибку:

$ python indentation.py
  File "indentation.py", line 5
    print('done')
                ^
IndentationError: unindent does not match any outer indentation level

Хотя трассировка выглядит во многом как трассировка + SyntaxError +, на самом деле это + IndentationError +. Сообщение об ошибке также очень полезно. Он говорит вам, что уровень отступа строки не соответствует ни одному другому уровню отступа. Другими словами, + print ('done') + это отступ с двумя пробелами, но Python не может найти любую другую строку кода, соответствующую этому уровню отступа. Вы можете быстро это исправить, убедившись, что код соответствует ожидаемому уровню отступа.

Другой тип + SyntaxError + — это + TabError + , который вы будете видеть всякий раз, когда есть строка, содержащая либо табуляцию, либо пробелы для отступа, в то время как остальная часть файла содержит другую. Это может скрыться, пока Python не покажет это вам!

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

 1 # indentation.py
 2 def foo():
 3     for i in range(10):
 4         print(i)
 5     print('done')
 6
 7 foo()

Здесь строка 5 имеет отступ вместо 4 пробелов. Этот блок кода может выглядеть идеально для вас, или он может выглядеть совершенно неправильно, в зависимости от настроек вашей системы.

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

$ tabs 4 # Sets the shell tab width to 4 spaces
$ cat -n indentation.py
     1   # indentation.py
     2   def foo():
     3       for i in range(10)
     4           print(i)
     5       print('done')
     6
     7   foo()

$ tabs 8 # Sets the shell tab width to 8 spaces (standard)
$ cat -n indentation.py
     1   # indentation.py
     2   def foo():
     3       for i in range(10)
     4           print(i)
     5           print('done')
     6
     7   foo()

$ tabs 3 # Sets the shell tab width to 3 spaces
$ cat -n indentation.py
     1   # indentation.py
     2   def foo():
     3       for i in range(10)
     4           print(i)
     5      print('done')
     6
     7   foo()

Обратите внимание на разницу в отображении между тремя примерами выше. Большая часть кода использует 4 пробела для каждого уровня отступа, но строка 5 использует одну вкладку во всех трех примерах. Ширина вкладки изменяется в зависимости от настройки tab width :

  • Если ширина вкладки равна 4 , то оператор + print + будет выглядеть так, как будто он находится вне цикла + for +. Консоль выведет + 'done' + в конце цикла.

  • Если ширина табуляции равна 8 , что является стандартным для многих систем, то оператор + print + будет выглядеть так, как будто он находится внутри цикла + for +. Консоль будет печатать + 'done' + после каждого числа.

  • Если ширина табуляции равна 3 , то оператор + print + выглядит неуместно. В этом случае строка 5 не соответствует ни одному уровню отступа.

Когда вы запустите код, вы получите следующую ошибку и трассировку:

$ python indentation.py
  File "indentation.py", line 5
    print('done')
                ^
TabError: inconsistent use of tabs and spaces in indentation

Обратите внимание на + TabError + вместо обычного + SyntaxError +. Python указывает на проблемную строку и дает вам полезное сообщение об ошибке. Это ясно говорит о том, что в одном и том же файле для отступа используется смесь вкладок и пробелов.

Решение этой проблемы состоит в том, чтобы все строки в одном и том же файле кода Python использовали либо табуляции, либо пробелы, но не обе. Для приведенных выше блоков кода исправление будет состоять в том, чтобы удалить вкладку и заменить ее на 4 пробела, которые будут печатать + 'done' + после завершения цикла + for +.

Определение и вызов функций

Вы можете столкнуться с неверным синтаксисом в Python, когда вы определяете или вызываете функции. Например, вы увидите + SyntaxError +, если будете использовать точку с запятой вместо двоеточия в конце определения функции:

>>>

>>> def fun();
  File "<stdin>", line 1
    def fun();
             ^
SyntaxError: invalid syntax

Трассировка здесь очень полезна, с помощью каретки, указывающей прямо на символ проблемы. Вы можете очистить этот неверный синтаксис в Python, отключив точку с запятой для двоеточия.

Кроме того, ключевые аргументы как в определениях функций, так и в вызовах функций должны быть в правильном порядке. Аргументы ключевых слов always идут после позиционных аргументов. Отказ от использования этого порядка приведет к + SyntaxError +:

>>>

>>> def fun(a, b):
...     print(a, b)
...
>>> fun(a=1, 2)
  File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument

Здесь, еще раз, сообщение об ошибке очень полезно, чтобы рассказать вам точно, что не так со строкой.

Изменение версий Python

Иногда код, который прекрасно работает в одной версии Python, ломается в более новой версии. Это связано с официальными изменениями в синтаксисе языка. Наиболее известным примером этого является оператор + print +, который перешел от ключевого слова в Python 2 к встроенной функции в Python 3:

>>>

>>> # Valid Python 2 syntax that fails in Python 3
>>> print 'hello'
  File "<stdin>", line 1
    print 'hello'
                ^
SyntaxError: Missing parentheses in call to 'print'. Did you mean print('hello')?

Это один из примеров, где появляется сообщение об ошибке, сопровождающее + SyntaxError +! Он не только сообщает вам, что в вызове + print + отсутствует скобка, но также предоставляет правильный код, который поможет вам исправить оператор.

Другая проблема, с которой вы можете столкнуться, — это когда вы читаете или изучаете синтаксис, который является допустимым синтаксисом в более новой версии Python, но недопустим в той версии, в которую вы пишете. Примером этого является синтаксис f-string, которого нет в версиях Python до 3.6:

>>>

>>> # Any version of python before 3.6 including 2.7
>>> w ='world'
>>> print(f'hello, {w}')
  File "<stdin>", line 1
    print(f'hello, {w}')
                      ^
SyntaxError: invalid syntax

В версиях Python до 3.6 интерпретатор ничего не знает о синтаксисе f-строки и просто предоставляет общее сообщение «» неверный синтаксис «`. Проблема, в данном случае, в том, что код looks прекрасно работает, но он был запущен с более старой версией Python. В случае сомнений перепроверьте, какая версия Python у вас установлена!

Синтаксис Python продолжает развиваться, и в Python 3.8 появилось несколько интересных новых функций:

  • Walrus оператор (выражения присваивания)

  • F-string синтаксис для отладки
    *https://docs.python.org/3.8/whatsnew/3.8.html#positional-only-parameters[Positional-only arguments]

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

Python 3.8 также предоставляет новый* + SyntaxWarning + *. Вы увидите это предупреждение в ситуациях, когда синтаксис допустим, но все еще выглядит подозрительно. Примером этого может быть отсутствие запятой между двумя кортежами в списке. Это будет действительный синтаксис в версиях Python до 3.8, но код вызовет + TypeError +, потому что кортеж не может быть вызван:

>>>

>>> [(1,2)(2,3)]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object is not callable

Этот + TypeError + означает, что вы не можете вызывать кортеж, подобный функции, что, как думает интерпретатор Python, вы делаете.

В Python 3.8 этот код все еще вызывает + TypeError +, но теперь вы также увидите + SyntaxWarning +, который указывает, как вы можете решить проблему:

>>>

>>> [(1,2)(2,3)]
<stdin>:1: SyntaxWarning: 'tuple' object is not callable; perhaps you missed a comma?
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: 'tuple' object is not callable

Полезное сообщение, сопровождающее новый + SyntaxWarning +, даже дает подсказку (" возможно, вы пропустили запятую? "), Чтобы указать вам правильное направление!

Заключение

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

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

Получение + SyntaxError + во время изучения Python может быть неприятным, но теперь вы знаете, как понимать сообщения трассировки и с какими формами недопустимого синтаксиса в Python вы можете столкнуться. В следующий раз, когда вы получите + SyntaxError +, у вас будет больше возможностей быстро решить проблему!

To fix the SyntaxError: f-string: unmatched ‘(‘ in Python, you need to pay attention to use single or double quotes in f-string. You can change it or not use it. Please read the following article for details. 

New built-in string formatting method from Python 3.6 in the following syntax:

f''a{value:pattern}b''

Parameters:

  • f character: use the string f to format the string.
  • a,b: characters to format.
  • {value:pattern}: string elements need to be formatted.
  • pattern: string format.

In simple terms, we format a string in Python by writing the letter f or F in front of the string and then assigning a replacement value to the replacement field. We then transform the replacement value assigned to match the format in the replace field and complete the process.

The SyntaxError: f-string: unmatched ‘(‘ in Python happens because you use unreasonable single or double quotes in f-string.

Example: 

testStr = 'visit learnshareit website'

# Put variable name with the string in double quotes in f-string for formatting
newStr = f"{(testStr + "hello")}"
print(newStr)

Output:

  File "code.py", line 4
    newStr = f"{(testStr + "hello")}"
                            ^
SyntaxError: invalid syntax

How to solve this error?

Change the quotes

The simplest way is to change the quotes. If your f-string contains double quotes, put the string inside it with single quotes.

Example:

testStr = 'visit learnshareit website'

# Use single quotes for strings in f-string when f-string contains double quotes
newStr = f"{(testStr + ' hello')}"
print(newStr)

Output:

visit learnshareit website hello

Similarly, we will do the opposite if the f-string carries single quotes. The string in it must carry double quotes.

Example:

testStr = 'visit learnshareit website'

# f-string contains single quotes. The string must contain double quotes
newStr = f'{(testStr + " hello")}'
print(newStr)

Output:

visit learnshareit website hello

Do not use single or double quotes

If the problem is with quotes confusing you, limit their use inside the f-string.

Example:

  • I want to concatenate two strings instead of using quotes inside the f-string. Then I declare 2 variables containing two strings and use the addition operator to concatenate two strings inside f-string so that will avoid SyntaxError: f- string: unmatched ‘(‘.
testStr = 'visit learnshareit website'
secondStr = '!!!'

newStr = f'{ testStr + secondStr }'
print(newStr)

Output:

visit learnshareit website!!!

Summary

The SyntaxError: f-string: unmatched ‘(‘ in Python has been resolved. You can use one of two methods above for this problem. If there are better ways, please leave a comment. We appreciate this. Thank you for reading!

Maybe you are interested:

  • How To Resolve SyntaxError: ‘Break’ Outside Loop In Python
  • How To Resolve SyntaxError: f-string: Empty Expression Not Allowed In Python
  • How To Resolve SyntaxError: F-string Expression Part Cannot Include A Backslash In Python

Jason Wilson

My name is Jason Wilson, you can call me Jason. My major is information technology, and I am proficient in C++, Python, and Java. I hope my writings are useful to you while you study programming languages.


Name of the university: HHAU
Major: IT
Programming Languages: C++, Python, Java

#База знаний

  • 10 июн 2021

  • 14

Ваши строки никогда не были такими ясными, мощными, красивыми.

художественно-промышленная академия имени А. Л. Штиглица

Цокто Жигмытов

Кандидат философских наук, специалист по математическому моделированию. Пишет про Data Science, AI и программирование на Python.

Форматирование и вывод строк — одна из наиболее типичных задач в любом языке программирования. Однако в Python до версии 3.6 у нас было, по большому счёту, всего два способа:

  • оператор %;
  • функция format().

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

str_1 = "Name: %s, email: %s, phone: %s" % (name, email, phone)
str_2 = "Name: {}, email: {}, phone: {}".format(name, email, phone)

Что там говорят на вводных уроках про читаемость кода в Python?

Первый вариант никуда не годен: мало того что надо бегать глазами туда-сюда по строке, — надо ещё помнить о ключах после символа % (для разных типов они разные, s — для строк) и не забыть поставить ещё один % между строкой и кортежем с переменными.

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

Так жить нельзя, решил однажды Гвидо ван Россум, и в версии 3.6 появились
f-strings, они же formatted string literals, — литералы форматированных строк. Или просто форматированные строки, эф-строки, или даже, не побоимся этого слова, эф-стринги. Строки в Python’е стали «питоничнее» — компактнее, удобнее, читаемее.

Синтаксис форматированных строк прост и прям. Вы добавляете перед строкой, прямо перед открывающими двойными или одинарными кавычками, букву f. Всё, строка теперь форматированная.

print(f"Hello f-strings")
>>> Hello f-string

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

name = "f-strings"  # переменная
print(f"Hello {name}")
>>> Hello f-strings

Правда ведь, стало проще и яснее? Не надо бегать взглядом в конец строки и обратно, чтобы понять, где и какая переменная выводится: всё прямо под рукой и перед глазами. И это только самое начало, едем дальше.

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

num = 7
print(f'{num} в квадрате равно {num * num}')
>>> 7 в квадрате равно 49

Вызовем строковую функцию .upper(), превращающую все буквы строки в заглавные:

name = "спарта"
print(f"Это {name.upper()}!!!")
>>> Это СПАРТА!!!

Думаем, принцип ясен. Вот ещё пример с вызовом элементов словаря.

dict = {'name': 'Коля', 'profession': 'программист'}
print(f"{dict['name']} - это наш {dict['profession']}")
>>> Коля - это наш программист

Обратите внимание, что для строки и для ключей словаря вам нужно использовать разные кавычки. Например, двойные кавычки для f-строки и одинарные для ключей, как выше, или наоборот. Иначе будет синтаксическая ошибка — Python не поймёт, где строка, а где параметр.

Но что, если нужно напечатать оба вида кавычек? Для начала можно попробовать старый добрый бэкслеш, или обратную косую черту. Она изолирует символ, идущий за ней, и позволяет вывести те же самые кавычки, которые оформляют основную строку.

print(f"Привет, "{name}", я 'Саша'")
>>> Привет, "Коля", я 'Саша'

Но внутри фигурных скобок форматированной строки бэкслеш не поддерживается. Увы. Поэтому следующий код вызовет ошибку:

list_a = ['a', 'b', 'c']
print(f"{'n'.join(list_a)}")
>>> SyntaxError: f-string expression part cannot include a backslash

Наиболее простой и разумный путь избежать этого — вычислить выражение с бэкслешем заранее и только затем передать его в форматированную строку:

x = "n".join(list_a)
print(f"{x}")
>>> a
>>> b
>>> c

Аналогично: что, если нам нужно вывести фигурные скобки в форматированной строке? Для начала стоит заметить, что фигурные скобки в f-строках не могут быть пустыми.

print(f'{}')
>>> SyntaxError: f-string: empty expression not allowed

Однако мы можем заполнить пустые фигурные скобки другими фигурными скобками.

print(f'А вот фигурные скобки: {{}}')
>>> А вот фигурные скобки: {}

Главная хитрость: выражения внутри «самых внутренних» фигурных скобок вычисляются только в том случае, если у нас нечётное количество пар этих скобок.

f'{{4 + 4}}'  # две пары фигурных скобок, выражение не вычисляется
>>> '{4 + 4}'
f'{{{4 + 4}}}'  # три пары скобок, выражение вычисляется
>>> '{8}'

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

f'{value:{width}.{precision}}'

Значение, двоеточие, затем ширина строки в фигурных скобках, точка, требуемая точность в фигурных скобках.

Для начала давайте посмотрим, как задать точность вывода значения.

pi = 3.14159265
print(f'{pi:.2f}')
>>> 3.

Если в параметре precision указать 2f, как здесь, то значение выводится с двумя знаками после запятой. Буква f в данном случае означает fractional part, то есть дробную часть числа. Если оставить просто 2, то значение целиком — и целая, и дробная часть — будет занимать два знака (точка не считается).

print(f'{pi:.2}')
>>> 3.1

Параметр width, стоящий в фигурных скобках после двоеточия и перед точкой, определяет ширину строки, выделенной под значение, и выравнивание в ней.

print(f'{5:<5}₽')  # ширина 5 символов, выравниванием влево <
>>> 5	   ₽
print(f'{5:>5}₽')  # ширина 5 символов, выравниванием вправо >
>>>    5

Если не указать направление выравнивания (< или >), то строка по умолчанию будет выравниваться по левому краю (<).

Генерация списков, словарей и множеств командами в одну строку — наиболее мощные и характерные фичи языка Python. Всё это великолепие работает и с форматированными строками. Вот список из форматированных строк, созданный на основе другого списка:

list_b = ['a', 'b', 'c', 'd']
[f'{x + x}' for x in list_b]
>>> ['aa', 'bb', 'cc', 'dd']

Форматированная строка может содержать и генератор списка, с этим проблем нет, — тогда она выдаст строку, состоящую из вычисленного списка, а не из команды генератора.

f'{[x + x for x in list_b]}'
>>> "['aa', 'bb', 'cc', 'dd']"

Со словарями и множествами дело обстоит чуть иначе — в основном из-за наличия фигурных скобок. Поэтому для того, чтобы строка была в виде словаря, а не в виде текста генератора, надо добавлять пробелы между внутренними и внешними фигурными скобками.

f"{{n: n**2 for n in range(5)}}"  # выведет строку генератора
>>> '{n: n**2 for n in range(5)}'

f"{ {n: n**2 for n in range(5)} }"  # добавили пробелы, сработало!
>>> '{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}'

f"{ {n**2 for n in range(3)} }"  # генератор → множество → строка
>>> '{0, 1, 4}'

Форматированная строка — скромный и не всегда заметный, но удобный и мощный инструмент в арсенале питониста. Используйте форматированные строки, если:

  • вам важно, как выглядит вывод программы;
  • вы хотите повысить читаемость вашего кода.

А также в любой другой непонятной ситуации.

На курсе «Профессия Python-разработчик» вы узнаете много других, не менее мощных фишек языка и станете по-настоящему продвинутым питонистом. Приходите!

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

Участвовать

Школа дронов для всех
Учим программировать беспилотники и управлять ими.

Узнать больше

Author:
Eric V. Smith <eric at trueblade.com>
Status:
Final
Type:
Standards Track
Created:
01-Aug-2015
Python-Version:
3.6
Post-History:
07-Aug-2015, 30-Aug-2015, 04-Sep-2015, 19-Sep-2015, 06-Nov-2016
Resolution:
Python-Dev message

Table of Contents

  • Abstract
  • Rationale
    • No use of globals() or locals()
  • Specification
    • Escape sequences
    • Code equivalence
    • Expression evaluation
    • Format specifiers
    • Concatenating strings
    • Error handling
    • Leading and trailing whitespace in expressions is ignored
    • Evaluation order of expressions
  • Discussion
    • python-ideas discussion
      • How to denote f-strings
      • How to specify the location of expressions in f-strings
      • Supporting full Python expressions
    • Similar support in other languages
    • Differences between f-string and str.format expressions
    • Triple-quoted f-strings
    • Raw f-strings
    • No binary f-strings
    • !s, !r, and !a are redundant
    • Lambdas inside expressions
    • Can’t combine with ‘u’
  • Examples from Python’s source code
  • References
  • Copyright

Abstract

Python supports multiple ways to format text strings. These include
%-formatting [1], str.format() [2], and string.Template
[3]. Each of these methods have their advantages, but in addition
have disadvantages that make them cumbersome to use in practice. This
PEP proposed to add a new string formatting mechanism: Literal String
Interpolation. In this PEP, such strings will be referred to as
“f-strings”, taken from the leading character used to denote such
strings, and standing for “formatted strings”.

This PEP does not propose to remove or deprecate any of the existing
string formatting mechanisms.

F-strings provide a way to embed expressions inside string literals,
using a minimal syntax. It should be noted that an f-string is really
an expression evaluated at run time, not a constant value. In Python
source code, an f-string is a literal string, prefixed with ‘f’, which
contains expressions inside braces. The expressions are replaced with
their values. Some examples are:

>>> import datetime
>>> name = 'Fred'
>>> age = 50
>>> anniversary = datetime.date(1991, 10, 12)
>>> f'My name is {name}, my age next year is {age+1}, my anniversary is {anniversary:%A, %B %d, %Y}.'
'My name is Fred, my age next year is 51, my anniversary is Saturday, October 12, 1991.'
>>> f'He said his name is {name!r}.'
"He said his name is 'Fred'."

A similar feature was proposed in PEP 215. PEP 215 proposed to support
a subset of Python expressions, and did not support the type-specific
string formatting (the __format__() method) which was introduced
with PEP 3101.

Rationale

This PEP is driven by the desire to have a simpler way to format
strings in Python. The existing ways of formatting are either error
prone, inflexible, or cumbersome.

%-formatting is limited as to the types it supports. Only ints, strs,
and doubles can be formatted. All other types are either not
supported, or converted to one of these types before formatting. In
addition, there’s a well-known trap where a single value is passed:

>>> msg = 'disk failure'
>>> 'error: %s' % msg
'error: disk failure'

But if msg were ever to be a tuple, the same code would fail:

>>> msg = ('disk failure', 32)
>>> 'error: %s' % msg
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: not all arguments converted during string formatting

To be defensive, the following code should be used:

>>> 'error: %s' % (msg,)
"error: ('disk failure', 32)"

str.format() was added to address some of these problems with
%-formatting. In particular, it uses normal function call syntax (and
therefore supports multiple parameters) and it is extensible through
the __format__() method on the object being converted to a
string. See PEP 3101 for a detailed rationale. This PEP reuses much of
the str.format() syntax and machinery, in order to provide
continuity with an existing Python string formatting mechanism.

However, str.format() is not without its issues. Chief among them
is its verbosity. For example, the text value is repeated here:

>>> value = 4 * 20
>>> 'The value is {value}.'.format(value=value)
'The value is 80.'

Even in its simplest form there is a bit of boilerplate, and the value
that’s inserted into the placeholder is sometimes far removed from
where the placeholder is situated:

>>> 'The value is {}.'.format(value)
'The value is 80.'

With an f-string, this becomes:

>>> f'The value is {value}.'
'The value is 80.'

F-strings provide a concise, readable way to include the value of
Python expressions inside strings.

In this sense, string.Template and %-formatting have similar
shortcomings to str.format(), but also support fewer formatting
options. In particular, they do not support the __format__
protocol, so that there is no way to control how a specific object is
converted to a string, nor can it be extended to additional types that
want to control how they are converted to strings (such as Decimal
and datetime). This example is not possible with
string.Template:

>>> value = 1234
>>> f'input={value:#06x}'
'input=0x04d2'

And neither %-formatting nor string.Template can control
formatting such as:

>>> date = datetime.date(1991, 10, 12)
>>> f'{date} was on a {date:%A}'
'1991-10-12 was on a Saturday'

No use of globals() or locals()

In the discussions on python-dev [4], a number of solutions where
presented that used locals() and globals() or their equivalents. All
of these have various problems. Among these are referencing variables
that are not otherwise used in a closure. Consider:

>>> def outer(x):
...     def inner():
...         return 'x={x}'.format_map(locals())
...     return inner
...
>>> outer(42)()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<stdin>", line 3, in inner
KeyError: 'x'

This returns an error because the compiler has not added a reference
to x inside the closure. You need to manually add a reference to x in
order for this to work:

>>> def outer(x):
...     def inner():
...         x
...         return 'x={x}'.format_map(locals())
...     return inner
...
>>> outer(42)()
'x=42'

In addition, using locals() or globals() introduces an information
leak. A called routine that has access to the callers locals() or
globals() has access to far more information than needed to do the
string interpolation.

Guido stated [5] that any solution to better string interpolation
would not use locals() or globals() in its implementation. (This does
not forbid users from passing locals() or globals() in, it just
doesn’t require it, nor does it allow using these functions under the
hood.)

Specification

In source code, f-strings are string literals that are prefixed by the
letter ‘f’ or ‘F’. Everywhere this PEP uses ‘f’, ‘F’ may also be
used. ‘f’ may be combined with ‘r’ or ‘R’, in either order, to produce
raw f-string literals. ‘f’ may not be combined with ‘b’: this PEP does
not propose to add binary f-strings. ‘f’ may not be combined with ‘u’.

When tokenizing source files, f-strings use the same rules as normal
strings, raw strings, binary strings, and triple quoted strings. That
is, the string must end with the same character that it started with:
if it starts with a single quote it must end with a single quote, etc.
This implies that any code that currently scans Python code looking
for strings should be trivially modifiable to recognize f-strings
(parsing within an f-string is another matter, of course).

Once tokenized, f-strings are parsed in to literal strings and
expressions. Expressions appear within curly braces '{' and
'}'. While scanning the string for expressions, any doubled
braces '{{' or '}}' inside literal portions of an f-string are
replaced by the corresponding single brace. Doubled literal opening
braces do not signify the start of an expression. A single closing
curly brace '}' in the literal portion of a string is an error:
literal closing curly braces must be doubled '}}' in order to
represent a single closing brace.

The parts of the f-string outside of braces are literal
strings. These literal portions are then decoded. For non-raw
f-strings, this includes converting backslash escapes such as
'n', '"', "'", 'xhh', 'uxxxx',
'Uxxxxxxxx', and named unicode characters 'N{name}' into
their associated Unicode characters [6].

Backslashes may not appear anywhere within expressions. Comments,
using the '#' character, are not allowed inside an expression.

Following each expression, an optional type conversion may be
specified. The allowed conversions are '!s', '!r', or
'!a'. These are treated the same as in str.format(): '!s'
calls str() on the expression, '!r' calls repr() on the
expression, and '!a' calls ascii() on the expression. These
conversions are applied before the call to format(). The only
reason to use '!s' is if you want to specify a format specifier
that applies to str, not to the type of the expression.

F-strings use the same format specifier mini-language as str.format.
Similar to str.format(), optional format specifiers maybe be
included inside the f-string, separated from the expression (or the
type conversion, if specified) by a colon. If a format specifier is
not provided, an empty string is used.

So, an f-string looks like:

f ' <text> { <expression> <optional !s, !r, or !a> <optional : format specifier> } <text> ... '

The expression is then formatted using the __format__ protocol,
using the format specifier as an argument. The resulting value is
used when building the value of the f-string.

Note that __format__() is not called directly on each value. The
actual code uses the equivalent of type(value).__format__(value,
format_spec)
, or format(value, format_spec). See the
documentation of the builtin format() function for more details.

Expressions cannot contain ':' or '!' outside of strings or
parentheses, brackets, or braces. The exception is that the '!='
operator is allowed as a special case.

Escape sequences

Backslashes may not appear inside the expression portions of
f-strings, so you cannot use them, for example, to escape quotes
inside f-strings:

>>> f'{'quoted string'}'
  File "<stdin>", line 1
SyntaxError: f-string expression part cannot include a backslash

You can use a different type of quote inside the expression:

>>> f'{"quoted string"}'
'quoted string'

Backslash escapes may appear inside the string portions of an
f-string.

Note that the correct way to have a literal brace appear in the
resulting string value is to double the brace:

>>> f'{{ {4*10} }}'
'{ 40 }'
>>> f'{{{4*10}}}'
'{40}'

Like all raw strings in Python, no escape processing is done for raw
f-strings:

>>> fr'x={4*10}n'
'x=40\n'

Due to Python’s string tokenizing rules, the f-string
f'abc {a['x']} def' is invalid. The tokenizer parses this as 3
tokens: f'abc {a[', x, and ']} def'. Just like regular
strings, this cannot be fixed by using raw strings. There are a number
of correct ways to write this f-string: with a different quote
character:

Or with triple quotes:

Code equivalence

The exact code used to implement f-strings is not specified. However,
it is guaranteed that any embedded value that is converted to a string
will use that value’s __format__ method. This is the same
mechanism that str.format() uses to convert values to strings.

For example, this code:

f'abc{expr1:spec1}{expr2!r:spec2}def{expr3}ghi'

Might be evaluated as:

'abc' + format(expr1, spec1) + format(repr(expr2), spec2) + 'def' + format(expr3) + 'ghi'

Expression evaluation

The expressions that are extracted from the string are evaluated in
the context where the f-string appeared. This means the expression has
full access to local and global variables. Any valid Python expression
can be used, including function and method calls.

Because the f-strings are evaluated where the string appears in the
source code, there is no additional expressiveness available with
f-strings. There are also no additional security concerns: you could
have also just written the same expression, not inside of an
f-string:

>>> def foo():
...   return 20
...
>>> f'result={foo()}'
'result=20'

Is equivalent to:

>>> 'result=' + str(foo())
'result=20'

Expressions are parsed with the equivalent of ast.parse('(' +
expression + ')', '<fstring>', 'eval')
[7].

Note that since the expression is enclosed by implicit parentheses
before evaluation, expressions can contain newlines. For example:

>>> x = 0
>>> f'''{x
... +1}'''
'1'

>>> d = {0: 'zero'}
>>> f'''{d[0
... ]}'''
'zero'

Format specifiers

Format specifiers may also contain evaluated expressions. This allows
code such as:

>>> width = 10
>>> precision = 4
>>> value = decimal.Decimal('12.34567')
>>> f'result: {value:{width}.{precision}}'
'result:      12.35'

Once expressions in a format specifier are evaluated (if necessary),
format specifiers are not interpreted by the f-string evaluator. Just
as in str.format(), they are merely passed in to the
__format__() method of the object being formatted.

Concatenating strings

Adjacent f-strings and regular strings are concatenated. Regular
strings are concatenated at compile time, and f-strings are
concatenated at run time. For example, the expression:

>>> x = 10
>>> y = 'hi'
>>> 'a' 'b' f'{x}' '{c}' f'str<{y:^4}>' 'd' 'e'

yields the value:

While the exact method of this run time concatenation is unspecified,
the above code might evaluate to:

'ab' + format(x) + '{c}' + 'str<' + format(y, '^4') + '>de'

Each f-string is entirely evaluated before being concatenated to
adjacent f-strings. That means that this:

Is a syntax error, because the first f-string does not contain a
closing brace.

Error handling

Either compile time or run time errors can occur when processing
f-strings. Compile time errors are limited to those errors that can be
detected when scanning an f-string. These errors all raise
SyntaxError.

Unmatched braces:

>>> f'x={x'
  File "<stdin>", line 1
SyntaxError: f-string: expecting '}'

Invalid expressions:

>>> f'x={!x}'
  File "<stdin>", line 1
SyntaxError: f-string: empty expression not allowed

Run time errors occur when evaluating the expressions inside an
f-string. Note that an f-string can be evaluated multiple times, and
work sometimes and raise an error at other times:

>>> d = {0:10, 1:20}
>>> for i in range(3):
...     print(f'{i}:{d[i]}')
...
0:10
1:20
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
KeyError: 2

or:

>>> for x in (32, 100, 'fifty'):
...   print(f'x = {x:+3}')
...
'x = +32'
'x = +100'
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ValueError: Sign not allowed in string format specifier

Leading and trailing whitespace in expressions is ignored

For ease of readability, leading and trailing whitespace in
expressions is ignored. This is a by-product of enclosing the
expression in parentheses before evaluation.

Evaluation order of expressions

The expressions in an f-string are evaluated in left-to-right
order. This is detectable only if the expressions have side effects:

>>> def fn(l, incr):
...    result = l[0]
...    l[0] += incr
...    return result
...
>>> lst = [0]
>>> f'{fn(lst,2)} {fn(lst,3)}'
'0 2'
>>> f'{fn(lst,2)} {fn(lst,3)}'
'5 7'
>>> lst
[10]

Discussion

python-ideas discussion

Most of the discussions on python-ideas [8] focused on three issues:

  • How to denote f-strings,
  • How to specify the location of expressions in f-strings, and
  • Whether to allow full Python expressions.

How to denote f-strings

Because the compiler must be involved in evaluating the expressions
contained in the interpolated strings, there must be some way to
denote to the compiler which strings should be evaluated. This PEP
chose a leading 'f' character preceding the string literal. This
is similar to how 'b' and 'r' prefixes change the meaning of
the string itself, at compile time. Other prefixes were suggested,
such as 'i'. No option seemed better than the other, so 'f'
was chosen.

Another option was to support special functions, known to the
compiler, such as Format(). This seems like too much magic for
Python: not only is there a chance for collision with existing
identifiers, the PEP author feels that it’s better to signify the
magic with a string prefix character.

How to specify the location of expressions in f-strings

This PEP supports the same syntax as str.format() for
distinguishing replacement text inside strings: expressions are
contained inside braces. There were other options suggested, such as
string.Template’s $identifier or ${expression}.

While $identifier is no doubt more familiar to shell scripters and
users of some other languages, in Python str.format() is heavily
used. A quick search of Python’s standard library shows only a handful
of uses of string.Template, but hundreds of uses of
str.format().

Another proposed alternative was to have the substituted text between
{ and } or between { and }. While this syntax would
probably be desirable if all string literals were to support
interpolation, this PEP only supports strings that are already marked
with the leading 'f'. As such, the PEP is using unadorned braces
to denoted substituted text, in order to leverage end user familiarity
with str.format().

Supporting full Python expressions

Many people on the python-ideas discussion wanted support for either
only single identifiers, or a limited subset of Python expressions
(such as the subset supported by str.format()). This PEP supports
full Python expressions inside the braces. Without full expressions,
some desirable usage would be cumbersome. For example:

>>> f'Column={col_idx+1}'
>>> f'number of items: {len(items)}'

would become:

>>> col_number = col_idx+1
>>> f'Column={col_number}'
>>> n_items = len(items)
>>> f'number of items: {n_items}'

While it’s true that very ugly expressions could be included in the
f-strings, this PEP takes the position that such uses should be
addressed in a linter or code review:

>>> f'mapping is { {a:b for (a, b) in ((1, 2), (3, 4))} }'
'mapping is {1: 2, 3: 4}'

Similar support in other languages

Wikipedia has a good discussion of string interpolation in other
programming languages [9]. This feature is implemented in many
languages, with a variety of syntaxes and restrictions.

Differences between f-string and str.format expressions

There is one small difference between the limited expressions allowed
in str.format() and the full expressions allowed inside
f-strings. The difference is in how index lookups are performed. In
str.format(), index values that do not look like numbers are
converted to strings:

>>> d = {'a': 10, 'b': 20}
>>> 'a={d[a]}'.format(d=d)
'a=10'

Notice that the index value is converted to the string 'a' when it
is looked up in the dict.

However, in f-strings, you would need to use a literal for the value
of 'a':

This difference is required because otherwise you would not be able to
use variables as index values:

>>> a = 'b'
>>> f'a={d[a]}'
'a=20'

See [10] for a further discussion. It was this observation that led to
full Python expressions being supported in f-strings.

Furthermore, the limited expressions that str.format() understands
need not be valid Python expressions. For example:

>>> '{i[";]}'.format(i={'";':4})
'4'

For this reason, the str.format() “expression parser” is not suitable
for use when implementing f-strings.

Triple-quoted f-strings

Triple quoted f-strings are allowed. These strings are parsed just as
normal triple-quoted strings are. After parsing and decoding, the
normal f-string logic is applied, and __format__() is called on
each value.

Raw f-strings

Raw and f-strings may be combined. For example, they could be used to
build up regular expressions:

>>> header = 'Subject'
>>> fr'{header}:s+'
'Subject:\s+'

In addition, raw f-strings may be combined with triple-quoted strings.

No binary f-strings

For the same reason that we don’t support bytes.format(), you may
not combine 'f' with 'b' string literals. The primary problem
is that an object’s __format__() method may return Unicode data that
is not compatible with a bytes string.

Binary f-strings would first require a solution for
bytes.format(). This idea has been proposed in the past, most
recently in PEP 461. The discussions of such a feature usually
suggest either

  • adding a method such as __bformat__() so an object can control
    how it is converted to bytes, or
  • having bytes.format() not be as general purpose or extensible
    as str.format().

Both of these remain as options in the future, if such functionality
is desired.

!s, !r, and !a are redundant

The !s, !r, and !a conversions are not strictly
required. Because arbitrary expressions are allowed inside the
f-strings, this code:

>>> a = 'some string'
>>> f'{a!r}'
"'some string'"

Is identical to:

>>> f'{repr(a)}'
"'some string'"

Similarly, !s can be replaced by calls to str() and !a by
calls to ascii().

However, !s, !r, and !a are supported by this PEP in order
to minimize the differences with str.format(). !s, !r, and
!a are required in str.format() because it does not allow the
execution of arbitrary expressions.

Lambdas inside expressions

Because lambdas use the ':' character, they cannot appear outside
of parentheses in an expression. The colon is interpreted as the start
of the format specifier, which means the start of the lambda
expression is seen and is syntactically invalid. As there’s no
practical use for a plain lambda in an f-string expression, this is
not seen as much of a limitation.

If you feel you must use lambdas, they may be used inside of parentheses:

>>> f'{(lambda x: x*2)(3)}'
'6'

Can’t combine with ‘u’

The ‘u’ prefix was added to Python 3.3 in PEP 414 as a means to ease
source compatibility with Python 2.7. Because Python 2.7 will never
support f-strings, there is nothing to be gained by being able to
combine the ‘f’ prefix with ‘u’.

Examples from Python’s source code

Here are some examples from Python source code that currently use
str.format(), and how they would look with f-strings. This PEP
does not recommend wholesale converting to f-strings, these are just
examples of real-world usages of str.format() and how they’d look
if written from scratch using f-strings.

Lib/asyncio/locks.py:

extra = '{},waiters:{}'.format(extra, len(self._waiters))
extra = f'{extra},waiters:{len(self._waiters)}'

Lib/configparser.py:

message.append(" [line {0:2d}]".format(lineno))
message.append(f" [line {lineno:2d}]")

Tools/clinic/clinic.py:

methoddef_name = "{}_METHODDEF".format(c_basename.upper())
methoddef_name = f"{c_basename.upper()}_METHODDEF"

python-config.py:

print("Usage: {0} [{1}]".format(sys.argv[0], '|'.join('--'+opt for opt in valid_opts)), file=sys.stderr)
print(f"Usage: {sys.argv[0]} [{'|'.join('--'+opt for opt in valid_opts)}]", file=sys.stderr)

References

Copyright

This document has been placed in the public domain.

Environment data

  • VSCode Info: Version: 1.34.0-insider
    Commit: 0ab39f4148f242e7b0802330385fc99b4845aa31
    Date: 2019-04-08T05:13:56.940Z
    Electron: 3.1.8
    Chrome: 66.0.3359.181
    Node.js: 10.2.0
    V8: 6.6.346.32
    OS: Linux x64 5.0.5-200.fc29.x86_64 (Fedora 29)
  • VS Code version: 1.34.0-insider (commit 0ab39f414)
  • Extension version (available under the Extensions sidebar): 2019.3.6558 (8 April 2019)
  • OS and version: Linux x64 5.0.5-200.fc29.x86_64 (Fedora 29)
  • Python version (& distribution if applicable, e.g. Anaconda): pypy3.5-6.0.0
  • Type of virtual environment used (N/A | venv | virtualenv | conda | …): pyenv
  • Relevant/affected Python packages and their versions: XXX

Expected behaviour

When using the new format string specifier, the code should be valid, and not display any problem.

Actual behaviour

When using the new format string specifier, the code is not valid, and displays the problems:

invalid syntax Python(parser-16) [24, 54]
Undefined variable: 'f' Python(undefined-variable) [24, 53]

In this screenshot, you can see the issues:
screenshot-parser-16-error

Steps to reproduce:

  1. create a new python file
  2. paste the following into the file:
print(f"I like the number {3}.")
  1. save and wait a few minutes (it takes a bit for the errors to be displayed.)

Logs

{
	"resource": "[...]/elastic_mixin.py",
	"owner": "_generated_diagnostic_collection_name_#1",
	"code": "parser-16",
	"severity": 8,
	"message": "invalid syntax",
	"source": "Python",
	"startLineNumber": 24,
	"startColumn": 54,
	"endLineNumber": 24,
	"endColumn": 71
}
{
	"resource": "[...]/elastic_mixin.py",
	"owner": "_generated_diagnostic_collection_name_#1",
	"code": "undefined-variable",
	"severity": 4,
	"message": "Undefined variable: 'f'",
	"source": "Python",
	"startLineNumber": 24,
	"startColumn": 53,
	"endLineNumber": 24,
	"endColumn": 54
}

Output from Console under the Developer Tools panel (toggle Developer Tools on under Help; turn on source maps to make any tracebacks be useful by running Enable source map support for extension debugging)

0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии

А вот еще интересные материалы:

  • Яшка сломя голову остановился исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного исправьте ошибки
  • Ясность цели позволяет целеустремленно добиваться намеченного где ошибка
  • Python exe ошибка приложения 0xc000007b
  • Python exception как получить текст ошибки