views:

135

answers:

6

Here's my code:

sentenceToTranslate = raw_input("Please write in the sentence you want to translate: ")
words = sentenceToTranslate.split(" ")

for word in words:
    if isVowel(word[0]):
        print "TEST"


def isVowel(letter):
    if letter.lower() == "a" or letter.lower() == "e" or letter.lower() == "i" or letter.lower() == "o" or letter.lower() == "u":
        return True
    else:
        return False

The error I get is:

NameError: name 'isVowel' is not defined

What am I doing wrong?

+5  A: 

The function hasn't been defined yet, so the name 'isVowel' doesn't have a function bound to it: that only happens at the time when you say "def".

Solution: move your code below the def isVowel(letter).

chpwn
Python doesn't have function prototypes like C++ does, does it? **Edit:** nevermind. I guess it's not really needed as long as the code isn't *executed* before it's defined (but it *can* still be defined *above*, right?)
Mark
Look up the "`__name__ == '__main__`" trick to see a good way to ensure your functions are defined before the main code is executed.
Daniel Roseman
+1  A: 

Python executes all the statements that you put in your module when it encounters them, from top to bottom. What happens is that you try to call isVowel before you have defined that function. The python interpreter has not reached that code yet.

If you put the definition of isVowel at the top of your file you will be able to call it.

Arlaharen
+2  A: 

Put the def isVowel definition at top.

You defined the function after it had already been called. Since, the source code is not compiled and interpreted at run-time, it does not check for this error.

Also, you can redefine the function as

def isVowel(letter):
    if letter.lower() in "aeiou":
        return True
    else:
        return False
N 1.1
A: 

I think you need to define the function first, then call it after it has been defined.

def isVowel(letter):
    if letter.lower() == "a" or letter.lower() == "e" or letter.lower() == "i" or letter.lower() == "o" or letter.lower() == "u":
        return True
    else:
        return False

sentenceToTranslate = raw_input("Please write in the sentence you want to translate: ")
words = sentenceToTranslate.split(" ")

for word in words:
    if isVowel(word[0]):
        print "TEST"

Often you will put the function definitions in another file, and import them to avoid these problems.

Eoin
A: 

Here are a couple of other points to make for a newbie Pythoner:

1) What is the point of writing this?

def isVowel():
    if boolean-expression:
        return True
    else:
        return False

You already have the True/False-ness captured in the value of the boolean expression, just:

def isVowel():
    return boolean-expression

2) Function calls are performance killers. Especially when you have such a limited set of items to check for, instead of calling .lower() so that you can check against "aeiou", check the character itself against both the lower and upper case letters, "aeiouAEIOU". Even though this is twice the length string to test for membership, it saves us the call to the lower() function.

Here are some performance test results:

import time
import string
time.clock()

reps = 100000
testString = (string.uppercase + string.lowercase) * reps

start = time.clock()
for c in testString:
    answer = c.lower() in "aeiou"
end = time.clock()
print end-start

start = time.clock()
for c in testString:
    answer = c in "aeiouAEIOU"
end = time.clock()
print end-start

start = time.clock()
for c in testString:
    pass
end = time.clock()

Prints:

3.27782246068
1.76839123408
0.713913919227

The third loop shows the time it takes just to iterate over the testString itself, so the time spent in the body of the loop (assuming pass takes negligible time) is:

2.563908541
1.054477315

By avoiding the lower() call, the second technique is more than twice as fast.

Paul McGuire
Not only is this unrelated to the question, it's promoting premature optimization.
Stefan Kendall
I guess I just got caught up in a similar thought process as DisplacedAussie in the question's comments, of offering some coding advice to a Python newcomer, except my comments needed more space than a comment would allow. Since DA had suggested `letter.lower() in "aeiou"` in place of the explicit character-by-character testing in the OP's question, I just wondered what the impact would be of checking against "AEIOUaeiou" and avoiding the call to `lower()`. It's interesting that Alex Martelli recently got called out for a similar "between X and Y, X is faster, therefore better" comment.
Paul McGuire
Paul, interesting or not, it's unfortunate that everyone's opinions are colored depending on their name and their reputation (outside and inside SO). Also, people tend to downvote when they don't *like* or *disagree* with an answer, while they should downvote when the answer is not helpful. The tooltip is a dead giveaway, but nobody seems to notice.
ΤΖΩΤΖΙΟΥ
+1  A: 

At the risk of being downvoted again, here is some further insight into these "define before use" requirements.

Note that the body of a function is not processed for the existence of symbols in until that function gets called. So you could write code like this:

def A():
    # calls B - even though B is defined later in the module
    B()

def B():
    # calls A
    A()

And this works just fine. The interpreter/compiler works top-down through the module, but when it sees a function or class definition, it processes the definition of the function, but not the function itself.

The reason your code failed was because the reference to isVowel was not within a function, but was at module scope. Code in the module that is not within a function is executed immediately, so the interpreter needs to be able to resolve any names based on what it has seen so far.

Paul McGuire