Python - Random baby name generator issues - (duplicating input, calling variables)
Question: I've been looking at this all afternoon and can't figure out why the gender
input is repeating itself despite only appearing to be called once. It's not
part of a loop that I can see either.

I've tried adding variables to act as a counter and tried using an if
statement to only run the input if the counter variable is less than 1, but
can't figure it out.

Edit: Thanks to the great feedback here, I found out that get_full_name was
causing the duplicating gender input in get_first_name - but now I'm running
into issues when trying to output the randomly generated first & middle names.

I figured setting the setFirst, setMiddle and setLast variables as globals,
but then I get a NameError. I also tried creating a new function to display
them, but that wasn't working either. I tried adding "self." (without the
quotes) either directly in the function() or one of the indents beneath it.

I'll display the error first, then the full code.

Error: Traceback (most recent call last):  
File "**init**.py", line 100, in main()  
File "**init**.py", line 92, in main  
print displayName(setFirst, setMiddle, setLast)  
NameError: global name 'setFirst' is not defined  

I also get name errors trying to concatenate setFirst, setMiddle and setLast
into another variable for the full name.

Here's the code:

    
    
    from os.path import abspath, join, dirname
    import random
    
    full_path = lambda filename: abspath(join(dirname(__file__), filename))
    
    
    FILES = {
        'first:male': full_path('dist.male.first'),
        'first:female': full_path('dist.female.first'),
        'last': full_path('dist.all.last'),
    }
    
    
    def get_name(filename):
        selected = random.random() * 90
        with open(filename) as name_file:
            for line in name_file:
                name, _, cummulative, _ = line.split()
                if float(cummulative) > selected:
                    return name
    
    
    def get_first_name(gender=None):
        global determine
        global setFirst
    
        print ("First name... Enter 1 for Male, 2 for Female or 3 to be surprised! ")
        determine = input()
    
        if determine == 1:
            gender = 'male'
        if determine == 2:
            gender = 'female'
        if determine == 3:
            print ("You want to be surprised!")
            gender = random.choice(('male', 'female'))
    
        return get_name(FILES['first:%s' % gender]).capitalize()
        setFirst = get_first_name()
        print setFirst + " "
    
    def get_middle_name(gender=None):
        global setMiddle
    
        if determine == 1:
            gender = 'male'
        if determine == 2:
            gender = 'female'
        if determine == 3:
            gender = random.choice(('male', 'female'))
    
        return get_name(FILES['first:%s' % gender]).capitalize()
        setMiddle = get_middle_name()
        print setMiddle + " "
    
    def get_last_name():
        global setLast
    
        #We will implicitly pass a Last Name until other issues are fixed
        return “Smith”
    
        setLast = get_last_name()
        print setLast
    
    def get_full_name(gender=None):
        return u"%s %s %s" % (get_first_name(gender), get_middle_name(gender), get_last_name())
    
    #def displayName(setFirst, setMiddle, setLast):
    #    print setFirst + " " + setMiddle + " " + setLast
    
    def main():
        #print u"%s %s %s" % (setFirst, setMiddle, setLast)
        #print displayName(setFirst, setMiddle, setLast)
    
        f = open('output', 'a') #append output to filename output
        f.write(get_full_name() + '\n') #and add a line break after each run
        f.close()
    
    if __name__ == "__main__":
        main()
    

Even if I try passing the variables to main() like:

    
    
    def main(setFirst, setMiddle, setLast):
    

It still gives the NameError about not being defined. What am I doing wrong?

I added this right under "import random", but now I'm getting some rogue
"None" displays - which leads me to believe there is a leak in the code
somewhere. Thoughts?

    
    
    setFirst = None
    setMiddle = None
    setLast = None
    

Here is the function I created to try to track it: def displayName(setFirst,
setMiddle, setLast):

    
    
    if setFirst == None:
        print ("Random Baby Name Generator")
    
    else:
        print setFirst
        print setMiddle
        print setLast
    
    if setMiddle == None:
        print ("Double check the middle name variable.")
    
    if setLast == None:
        print ("Double check the last name variable.")
    


Answer: You are calling `get_full_name()` twice, you need to save the results:

    
    
    def main():
        full_name = get_full_name()
        print(full_name)
        f = open('output', 'a') #append output to filename output
        f.write(full_name + '\n') #and add a line break after each run
        f.close()
    

You also have a few indentation issues as well, plus your use of globals is a
bit inefficient. Ideally, functions should do one - and only one - task; this
makes them easier to debug.

Try this different version of your code:

    
    
    from os.path import abspath, join, dirname
    import random
    
    full_path = lambda filename: abspath(join(dirname(__file__), filename))
    
    
    FILES = {
        'first:male': full_path('dist.male.first'),
        'first:female': full_path('dist.female.first'),
        'last': full_path('dist.all.last'),
    }
    
    GENDER_MAP = {'1': 'male', '2': 'female'}
    
    def get_gender():
        result = input('Select a gender: 1 for Male, 2 for Female or 3 to be surprised')
        if result not in ('1', '2', '3'):
           print('{} is not a valid choice, please try again'.format(result))
           return get_gender()
        if result == '3':
           return random.choice(('1', '2'))
        return result
    
    def get_name(filename):
        selected = random.random() * 90
        with open(filename) as name_file:
            for line in name_file:
                name, _, cummulative, _ = line.split()
                if float(cummulative) > selected:
                    return name
    
    def get_name_from_file(name_type='first', gender='male'):
        if name_type in ('first','middle',):
            name = get_name(FILES['{}:{}'.format(name_type, gender)]).capitalize()
        else:
            name = get_name(FILES['last']).capitalize()
        return name
    
    def get_full_name():
        gender = get_gender()
        gender_file = GENDER_MAP.get(gender, '')
        first_name = get_name_from_file('first', gender_file)
        middle_name = get_name_from_file('middle', gender_file)
        last_name = get_name_from_file('last')
    
        return '{} {} {}'.format(first_name, middle_name, last_name)
    
    if __name__ == '__main__':
        name = get_full_name()
        print(full_name)
        with open('output', 'a') as f:
           f.write('{}\n'.format(full_name))
        print('Done')
    

