Ross Baker
Ross Baker

Reputation: 21

Mapping a Boolean function over a list

I'm new to programming so this is probably a silly question!

I'm trying to write a function that takes a list of letter grades and returns a Boolean true or false depending on whether it is a passing grade

## Calculate total units passed

def unitPassed(letterGrade):
    if letterGrade == 'N':
        passed = False
    else:
        if letterGrade == 'NCN':
           passed = False
        else:
            if letterGrade == 'WN':
                passed = False
            else:
                True
    return passed

unitsPassed = map(unitPassed,courseGradeLetter)

I've attempted to do this by creating a function that tests if a grade is a passing grade, and then map this over a list of grade.

The problem is that I get the following error for a list that contains more than one element:

local variable 'passed' referenced before assignment

If I try it with a list containing one element I get the correct result.

Any ideas why this is?

Thanks.

--

Thanks everyone, your answers have helped me a lot!

Upvotes: 1

Views: 2642

Answers (4)

bruno desthuilliers
bruno desthuilliers

Reputation: 77942

Some have already pointed your error and posted the most pythonic solutions, but anyway - here's another code review, but this time a step by step one:

First point: learn to use elif instead of nesting if clauses in else clauses:

def unitPassed(letterGrade):
    if letterGrade == 'N':
        passed = False
    elif letterGrade == 'NCN':
        passed = False
    elif letterGrade == 'WN':
        passed = False
    else:
        passed = True
    return passed

As you can see this is already more readable.

Second point: in Python we favor "early returns" - ie, in this kind of tests, instead of setting a variable in all branches and returning it at the end, we return directly (which avoids elif/else chains etc):

def unitPassed(letterGrade):
    if letterGrade == 'N':
        return False
    if letterGrade == 'NCN':
        return False
    if letterGrade == 'WN':
        return False
    return True

Which makes the code even more straightforward.

And of course the last refactoring is to avoid the multiple tests when possible, as posted by Dadep and digitake (but using a tuple instead of a list because we dont need the overhead of a list here):

def unitPassed(letterGrade):
    return letterGrade not in ("N", "NCN", "WN")

Also, you are using map() in your code snippet but while map() is still perfectly valid and appropriate, the more idiomatic (and marginally faster) version here would be a list comprehension:

passed = [unitPassed(letter) for letter in courseGradeLetter]

And since unitPassed is now basically a simple short expression, you can just inline it (unless of course you need this function elsewhere):

passed = [letter not in ('N', 'NCN', 'NWN') for letter in courseGradeLetter]

Upvotes: 4

Kapil
Kapil

Reputation: 459

The error is in the 3rd else statement, i.e. in line 13.
Change True to passed = True

Also, you can make your function clean,

def unitPassed(letterGrade):
    if letterGrade == 'N':
        passed = False
    elif letterGrade == 'NCN':
        passed = False
    elif letterGrade == 'WN':
        passed = False
    else:
        passed = True
    return passed

Upvotes: 0

digitake
digitake

Reputation: 856

how about this

def unitPassed(letterGrade):
    return letterGrade not in ['N', 'NCN', 'WN']

unitsPassed = map(unitPassed,courseGradeLetter)

Upvotes: 2

Dadep
Dadep

Reputation: 2788

you can redefine your function as :

>>> def unitPassed(letterGrade):
...     GP=['N', 'NCN', 'WN']
...     if letterGrade in GP:
...         return False
...     return True
... 
>>> letterGrade='DE'
>>> unitPassed(letterGrade)
True
>>> letterGrade='NCN'
>>> unitPassed(letterGrade)
False

Upvotes: 0

Related Questions