Using namedtuple in class

Viewed 174

I am practicing on a piece of code from the O'Reily's book Fluent Python.

The piece of code is as followed:

import collections

    Card= collections.namedtuple('Card',['rank','suit']);

    class FrenchDeck:
        ranks=[str(n) for n in range (2,11)]+ list('JQKA')
        suits= 'spades diamonds clubs hearts'.split()

        def __init__(self):
            self._cards= [Card(rank,suit)   for rank in self.ranks
                                            for suit in self.suits]
        def __len__(self):
            return len(self._cards)

        def __getitem__(self,position):
            return self._cards[position]

I can see how the feature of namedtuple is used to assign each value in ranks to all suits.

As one of my own practices, I would like to ask for help about assigning values in this paradigm. Specifically, in this snippet, instead of giving one students four grades, what's the way to assign one students with their respective unique grade using the namedtuple feature? (e.g John-89, Jay-98, Joe-87, Joseph-91). The way I regurgitate from the sample in the book will still assign all grades to each students. Thanks a lot for your attention and help!

Student= collections.namedtuple('Student',['name','grade'])

studentname=["John","Jay","Joe","Joseph"]

class grade: 
    names= studentname
    grades=[89,98,87,91]

    def __init__(self):
        self._stud=[
        Student(name,grade) for name in self.names 
                            for grade in self.grades ]  

    def __len__(self):
        return len(self._stud)

    def __getitem__(self,position):
        return self._stud[position]
2 Answers

In the code from the book every suit has every value — it's a cartesian product of suits and values. In your code you only want a one-to-one mapping from students to grades. This is typically done with zip(). You can use zip(self.names, self.grades) and this will give you corresponding pairs. You can then get a list of Students with

self._stud=[Student(n, g) for n, g in zip(self.names, self.grades)]

You might also make your class so it doesn't depend on globals and takes lists of students and grades with something like:

import collections

Student = collections.namedtuple('Student',['name','grade'])

studentname = ["John","Jay","Joe","Joseph"]
grades = [89,98,87,91]

class Grades: 
    def __init__(self, names, grades):
        self._stud = [Student(n, g) for n, g in zip(names, grades)]

    def __len__(self):
        return len(self._stud)

    def __getitem__(self,position):
        return self._stud[position]

g = Grades(studentname, grades)

g._stud will be:

[
  Student(name='John', grade=89),
  Student(name='Jay', grade=98),
  Student(name='Joe', grade=87),
  Student(name='Joseph', grade=91)
]

This doesn't really have anythign to do with named tuples. With the cards, you created a new Card instance using each element of the product of ranks and suits.

For grade, you want to create a new Student instance using each element from the result of zipping names and grades together.

def __init__(self):
    self._stud=[Student(name,grade) 
                for name, grade in zip(self.names, self.grades)]
Related