0

Hi all I recently started learning Python collections module. When I was trying to implement namedtuple collections for practice I got an error. I tried searching for in the official Python documentation but could not find. Can you all please help me out.

The error I'm getting is that even though I'm specifying default values for some of my fields in namedtuple I'm getting

#Importing namedtuple from collections module
from collections import namedtuple

#Creating a Student namespace
Students = namedtuple('Student','Roll_No Name Marks Percentage Grad', defaults= 
[0,''])
Students._field_defaults

#Creating students
ram = Students._make([101,'Ram Lodhe',[95,88,98]])
shaym = Students._make([101,'Shyam Verma',[65,88,85]])
geeta = Students._make([101,'Geeta Laxmi',[86,90,60]])
venkat = Students._make([101,'Venkat Iyer',[55,75,68]])
ankita = Students._make([101,'Anikta Gushe',[88,90,98]])
 TypeError  Traceback (most recent call last)  
 ram = Students._make([101,'Ram Lodhe',[95,88,98]])  
 TypeError: Expected 5 arguments, got 3

Screenshot of Error

  • What is the actual error message? Please [edit] your question to include it. – Code-Apprentice May 19 '22 at 17:54
  • Do you really want `'Roll_No Name Marks Percentage Grad'` to be one thing? – Code-Apprentice May 19 '22 at 17:55
  • What is the different approach ? – Vishal Lade May 19 '22 at 17:57
  • You are only passing three arguments. You set up 5 fields. Try: `Students._make([101,'Ram Lodhe',*[95,88,98]])` – Mark May 19 '22 at 17:59
  • I'm not familiar with namedtuple and am looking into it further. So far I don't see a problem. The single string for the second argument appears to be correct. – Code-Apprentice May 19 '22 at 17:59
  • 1
    @Mark The OP also defines 2 defaults which should fill in the last two arguments. – Code-Apprentice May 19 '22 at 17:59
  • The text of the error message was sufficient. I'm also confused why you are seeing this error. I can duplicate it, but the documentation seems to say this shouldn't happen. – Code-Apprentice May 19 '22 at 18:03
  • 1
    The `._make()` method apparently bypasses the application of default values. The normal way of constructing a namedtuple instance is to simply call the class (with the values as individual parameters, rather than a sequence as required with `_make()`). – jasonharper May 19 '22 at 18:03
  • 1
    It's interesting that this difference with `_make()` is not documented. – Mark May 19 '22 at 18:06
  • Yes I have 5 fields but i have specified last 2 fields with default values that's why I'm sending only 3 arguments to _make() function – Vishal Lade May 19 '22 at 18:06
  • 1
    @Mark @jasonharper Perhaps this is a bug and the intended behavior is for `_make()` to use the defaults? – Code-Apprentice May 19 '22 at 18:11

2 Answers2

1

Per @jasonharper, _make() appears to bypass default values. So the fix is to construct the namedtuple directly:

ram = Students(101,'Ram Lodhe',[95,88,98])

Alternatively, you can manually pass the defaults to _make():

ram = Students._make([101,'Ram Lodhe',[95,88,98], *Students._field_defaults.values()])
Code-Apprentice
  • 81,660
  • 23
  • 145
  • 268
  • 1
    FWIW, the [docs](https://docs.python.org/3/library/collections.html#collections.namedtuple) specifically say: `To prevent conflicts with field names, the method and attribute names start with an underscore.` That doesn't suggest they are meant to be private. – Mark May 19 '22 at 18:07
  • Yes It did work that way. This statement *Students._field_defaults.values() is passing the default values to the list so the number of arguments is becoming 5 and error is not coming . Thank you @Code-Apprentice – Vishal Lade May 19 '22 at 18:22
  • @VishalLade The `*` in this context is called the "splat operator" in case you want to look at how it works. – Code-Apprentice May 19 '22 at 20:00
0

Your named tuple expects 5 tuple entries, however, you handed a list (which is one object) containing the last three entries. I modified your code (naming is awful, please change if you want to keep) and now it works.

Students = namedtuple('Student','Roll_No Name List_ofMarksPercentageGrad', defaults= 
[0,''])

As of now, I don't know any option to tell namedtuples that an entry is a list with named entries.

Tabea
  • 39
  • 1
  • 7
  • I'm pretty sure the list as one argument is entirely intentional. The OP is asking why aren't the defaults used for the last two arguments that aren't given explicitly. – Code-Apprentice May 19 '22 at 18:00
  • If I understand correctly, you are suggesting to remove the spaces in the field names? But then there are only 3 fields and the OP clearly wants all 5. – Code-Apprentice May 19 '22 at 18:01
  • Well, the list itself is one argument, there is no nested evaluation of the list elements. By making it one word, the namedtuple has now only three entries and the indexing of the list would indicate what information is set. This is merely explaining where the error comes from. If a nested tuple is the only resonable choice, a class might be a better option (or getting rid of the list, as you suggested) – Tabea May 19 '22 at 18:13
  • I'm pretty sure that the list as a single argument is intentional by the OP. – Code-Apprentice May 19 '22 at 19:59