5
def test_stats(team, *args):

    if not args:
          [do some stuff]
    else:

        team_fixtures = (Fixtures.objects.filter(home_team=team_details.id) | Fixtures.objects.filter(away_team=team_details.id))/
.filter(fixture_datetime__lt=datetime.now()).filter(fixture_datetime__year=args[0])

And for reference sake - args is:

date_year = datetime.now().year

for this query to work i need to reference args as

.filter(fixture_datetime__year=args[0])

because if I use

.filter(fixture_datetime__year=args)

I get the error:

int() argument must be a string, a bytes-like object or a number, not 'tuple'

I understand that it thinks it's a tuple even though it's only one value but when I do the following in terminal

type(date_year)

I get class back.

Why do I have to reference position here when it looks to be just one value returning?

erip
  • 16,374
  • 11
  • 66
  • 121
purchas
  • 349
  • 7
  • 19
  • 1
    `*args` is *always* a tuple. – David Zemens Dec 14 '15 at 14:19
  • I don't understand what you are asking. You seem to answer everything in your question already. If you provide exactly one argument `bar` to `foo(*args)` then `args == (bar,)`. But reading your post you already knew that. – timgeb Dec 14 '15 at 14:19
  • 1
    @timegb OP is asking why if he passes `date_year` in the function call, why it is passed as a tuple of length 1, instead of the integer. – David Zemens Dec 14 '15 at 14:20

2 Answers2

4

The *-prefixed argument is always a tuple. It captures 0 or more extra positional arguments. You can call your test_stats() function with 3 or 20 or 100 extra arguments (beyond the explicit team argument), and they all would be part of the args tuple in the function:

>>> def foo(*args): return args
...
>>> foo()
()
>>> foo(42)
(42,)
>>> foo(1, 2, 3)
(1, 2, 3)

If you wanted one optional argument, make it a keyword argument with a sentinel default, like None:

def test_stats(team, optional=None):
    if optional is None:
        # ...
    else:
        team_fixtures = (
            Fixtures.objects.filter(home_team=team_details.id) |
            Fixtures.objects.filter(away_team=team_details.id))
                .filter(fixture_datetime__lt=datetime.now())
                .filter(fixture_datetime__year=optional)
        )
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
1

If you know that you are receiving date as a second argument then explicitly define it in signature

def test_stats(team, date):

If you can pass there also something different then use keyword arguments

def test_stats(team, date=None, something_else=None):

*args should be used only if you want to pass sequence of arguments without creating a sequence beforehand

def get_integers(*args):
    return args


>>> get_integers(1, 3, 4, 8, 9, 11)
(1, 3, 4, 8, 9, 11)

*args is a tuple and **kwargs is a dictionary.

Rafał Łużyński
  • 7,083
  • 5
  • 26
  • 38