Unintentional trailing comma that creates a tuple

2019-04-23 15:53发布

问题:

In Python, leaving a trailing comma like this is, of course, not a SyntaxError:

In [1]: x = 1 ,

In [2]: x
Out[2]: (1,)

In [3]: type(x)
Out[3]: tuple

But, at the same time, if the trailing comma was put accidentally, it may be difficult to catch this kind of a "problem", especially for Python newcomers.

I am thinking if we can catch this kind of a "problem" early, statically, with the help of PyCharm smart code quality control features; mypy, pylint or flake8 static code analysis tools.

Or, another idea would be to restrict/highlight creating one item tuples implicitly without parenthesis. Is it possible?

回答1:

pylintalready detects this as a problem (as of version 1.7).

For example, here's my tuple.py:

"""Module docstring to satisfy pylint"""

def main():
    """The main function"""
    thing = 1,
    print(type(thing))

if __name__ == "__main__":
    main()
$ pylint tuple.py
No config file found, using default configuration
************* Module tuple
R:  5, 0: Disallow trailing comma tuple (trailing-comma-tuple)

------------------------------------------------------------------
Your code has been rated at 8.00/10 (previous run: 8.00/10, +0.00)

$ pylint --help-msg trailing-comma-tuple
No config file found, using default configuration
:trailing-comma-tuple (R1707): *Disallow trailing comma tuple*
  In Python, a tuple is actually created by the comma symbol, not by the
  parentheses. Unfortunately, one can actually create a tuple by misplacing a
  trailing comma, which can lead to potential weird bugs in your code. You
  should always use parentheses explicitly for creating a tuple. This message
  belongs to the refactoring checker. It can't be emitted when using Python <
  3.0.


回答2:

It's not an unintended behavior since the tuple operator is ,, not (). The role of parenthesis here is the same as in arithmetic expressions. So you can't restrict such creation in a Python interpreter, otherwise it would be some other language.

I agree that a trailing comma is sometimes unintentional. Lint tools like pylint are often able to catch such errors by means of general type inference (i.e. they see that you try to add a tuple to a number). (Also note that sometimes trailing commas are useful and less unintentional, e.g. in the_only_elem, = our_list.) Another option is to write you own simple linter that checks for something like line.rstrip().endswith(',') and '=' in line (the second check is to allow multi-line list declaration to some extent).