Python Newbie
Python Newbie

Reputation: 381

Syntax of passing arguments into args in reverse()

The following is a snippet from Django official tutorial.
Link is here: https://docs.djangoproject.com/en/3.0/intro/tutorial05/

class QuestionDetailViewTests(TestCase):
    def test_future_question(self):
        future_question = create_question(question_text ="future question", days=30)
        url = reverse('polls:detail',args = (future_question.id,))

args = (future_question.id,): this syntax is very strange to me. Why do we need brackets and coma here?

Upvotes: 2

Views: 274

Answers (2)

datalowe
datalowe

Reputation: 599

Willem already gave a great answer, but to give a more detail on the fundamental question:

This syntax is very foreign to me. Why do we need brackets and coma here?

It might be simpler to see what's going on by looking at this example in the vanilla Python shell:

>>> a = ('foo')
>>> type(a)
# outputs <class 'str'>
>>> b = ('foo',)
>>> type(b)
# outputs <class 'tuple'>

This behavior might be surprising to you (I know it was to me the first time I saw it). One might expect the parentheses () to have a similar relationship with tuples as brackets [] do with lists. But while for c = ['foo'], the brackets ensure that c is assigned a list, with c = ('foo'), the parentheses don't make any difference compared to c = 'foo'. In fact, if you want to create a tuple, you can do this:

>>> d = 'foo', 'bar'
>>> type(d)
# outputs <class 'tuple'>
>>> e = ('foo',)
>>> type(e)
# outputs <class 'tuple'>

As you can see, the parentheses aren't in themselves necessary for creating a tuple. You do however often need them to specify that the comma-separated values are meant to be interpreted as elements of a tuple. For example:

sum((3, 3))
# outputs 6

This works. However:

sum(3, 3)
# outputs TypeError: 'int' object is not iterable

In this case, Python thinks that the two 3's are to be interpreted as separate arguments in the function call, not as elements of a tuple.

Similarly, for:

reverse('polls:detail',args = (future_question.id,))

Just using args = future_question.id would mean that you just pass a single int instead of a collection, as Willem described. Also, reverse('polls:detail',args = future_question.id,) wouldn't work either, because Python would interpret that last comma as an 'argument separator', not as something indicating that future_question.id is an element of a tuple. So you need both the comma and the parentheses to tell Python that you want to pass a single-element tuple as an argument to the function.

Upvotes: 2

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476503

Why do we need brackets and coma here?

To wrap the future_question.id in a singleton tuple, a tuple with one element. It is however not necessary to use a tuple, you can for example use a list:

url = reverse('polls:detail', args=[future_question.id])

what is important is that it is an iterable, and that the future_question.id is an element. If you pass future_question.id directly, and the id is an int, then that would not make sense, since args expects a collection, and an int is not a collection.

Upvotes: 4

Related Questions