JoePythonKing
JoePythonKing

Reputation: 1210

Type(1,) returns int expected tuple

type(1,)
Out[1]: int
a=1,
a
Out[3]: (1,)
type(a)
Out[4]: tuple

I am using Python 3.6, and I am expecting type(1,) to return a tuple.

According to this link:

... a tuple with one item is constructed by following a value with a comma...

What am I missing?

Upvotes: 5

Views: 1537

Answers (2)

Paritosh Singh
Paritosh Singh

Reputation: 6246

The issue lies in how python has to interpret function arguments, while allowing the "quality of life" trailing comma. Functions are called with parentheses with comma separated arguments. When you pass type(1,), There is ambiguity between a comma separated argument with a trailing comma, and an actual tuple.

A simple example:

def test(x):
    print(x) 

test("hello") #Output: hello
test("hello",) #is also valid, Output: hello

To see how python is actually accepting the argument, you can use the repr function.

repr(1)
'1'
repr(1,)
'1'

To specifically ensure you pass a tuple as the first argument, you should wrap it in parenthesis and resolve ambiguity.

repr((1,))
'(1,)'
type((1,))
tuple

The reason why it works after assigning is because the ambiguity is resolved while storing the value as a tuple.

a = 1,
repr(a)
'(1,)'

Additional info

As for when trailing commas can be useful, we can refer to the relevant PEP8 section.

When trailing commas are redundant, they are often helpful when a version control system is used, when a list of values, arguments or imported items is expected to be extended over time. The pattern is to put each value (etc.) on a line by itself, always adding a trailing comma, and add the close parenthesis/bracket/brace on the next line.

Which means, you should never be putting redundant trailing commas in a single line.

#No good
func_with_future_changes_or_variable_args(arg1, arg2=True,)

#Good
func_with_future_changes_or_variable_args(arg1,
                                          arg2=True,
                                          )

I personally don't run into much issues with functions that change, but trailing commas are life-savers when maintaining lists or dictionaries that can change over time. For example:

FILES = [
    'setup.cfg',
    'tox.ini',
    ]

Adding or removing values from a list like that only requires changing a single line in isolation like following, making it really easy to track in version control commits.

 FILES = [
     'setup.cfg',
     'tox.ini',
+    'new_item.txt',
    ]

Upvotes: 9

amanb
amanb

Reputation: 5463

From the docs:

Tuples may be constructed in a number of ways:

  1. Using a pair of parentheses to denote the empty tuple: ()
  2. Using a trailing comma for a singleton tuple: a, or (a,)
  3. Separating items with commas: a, b, c or (a, b, c)
  4. Using the tuple() built-in:tuple() or tuple(iterable)

According to this, all of the following are tuples. You will notice explicit assignment to a variable removes all ambiguities:

In [8]: a = ()
In [9]: type(a)
Out[9]: tuple    
In [10]: b = (1,)    
In [11]: type(b)
Out[11]: tuple    
In [12]: b = 1,    
In [13]: type(b)
Out[13]: tuple

When we look at type(1,), we should keep in mind that type() is a function and the trailing comma is an argument separator. The 1 is the first argument which is an integer and as trailing commas are allowed in Python, this is a valid statement but much less explicit. According to the official docs for type(), it is recommended to use the built-in isinstance function for type-checking which is more explicit:

In [21]: isinstance((1,), tuple)
Out[21]: True

Upvotes: 0

Related Questions