NameError: name 'uinput' is not defined error in Python - python

I'm trying to make a simple CLI app for todo-lists. What's happening here? Is it because I'm referring to a variable that's inside a function?
I've tried putting "global" behind uinput, but that said that the "=" was not valid syntax or something along those lines. Not quite sure why, I've also tried looking around for a while on google and couldn't find anything, sorry if it is obvious.
userlist = []
def maininput():
uinput = input("What would you like to add to your list?")
userlist.append(uinput)
for i in userlist:
print(userlist)
break
while uinput != "exit":
maininput()
What I would like that happened was that "uinput" could be recognized to do the while statement

You should declare your uinput in your function globally in a such way:
global uinput
uinput = input("...")
In global scope(before declraring a function) you should specify a value for uinput
uinput = input("...")
Intead of ... you should fill in your input prompt

Use a while True loop to break your list inside maininput, instead of using a global like below. Also you can print the list directly using print(userlist), instead of a for loop
userlist = []
def maininput():
while True:
uinput = input("What would you like to add to your list? Type exit to stop>>")
#Exit the loop when you type exit
if uinput == "exit":
break
#Else append to list and print it
userlist.append(uinput)
print(userlist)
#Call the main function
maininput()
The outputs will look like
What would you like to add to your list? Type exit to stop>>a
['a']
What would you like to add to your list? Type exit to stop>>b
['a', 'b']
What would you like to add to your list? Type exit to stop>>c
['a', 'b', 'c']
What would you like to add to your list? Type exit to stop>>d
['a', 'b', 'c', 'd']
What would you like to add to your list? Type exit to stop>>exit

Short answer: yes, it's because you are referring to a name that's defined inside a function. You are now aware of a concept called "scoping."
Inside any Python function, names are resolved by looking in three places in order:
The function call's local namespace, created when the function
is called and destroyed when it returns or otherwise exits;
The module's global namespace, which is where top-level classes and
functions are defined;
The built-in namespace, which contains Python's pre-defined values like
None, Exception - all the names that are a part of the Python language.
Outside a function, statements (sometimes referred to as top-level statements) the local and global namespaces are the same.
When the interpreter compiles a function call, any names that are bound (by assigning them a value, or defining a nested class or function) are assumed to be local to that call. This is why the top-level statements couldn't reference uinput.
Other answers have given you some insight into a better looping structure. I'd encourage you, as your skill level grows, to investigate modules like pickle and shelve or even dbm, which will let your to-do lists stay alive between program runs.

You place the last input word in userlist, and it's easy to access userlist contents from the main loop because ① userlist is initialized in the main ② when the function search for a list to which append the user's input it finds userlist in the outer scope and ③ userlist is a mutable object, whose changes are visible from every point in its scope.
userlist = []
def ask():
new = input('...')
userlist.append(new)
if new == 'exit' : return
print('List contains', ', '.join(s for s in userlist))
while userlist[-1:] != ['exit']:
ask()
(we write the test like this: userlist[-1:] != ['exit'] because at the first pass userlist is empty and indexing it, rather than extracting a slice, would raise an error).
Of course this is BAD PRACTICE because we introduce a strong coupling between the main and the function, it's much better to pass explicitly the list in the argument list:
userlist = []
def update_list(a_list):
new = input('...')
a_list.append(new)
if new == 'exit' : return
print('List contains', ', '.join(s for s in a_list))
while userlist[-1:] != ['exit']:
update_list(userlist)

Related

Can you call/use a function returned from a list in Python?

I'm trying to store a function in a list, retrieve the function from the list later, and then call on that function. This is basically what I want to do, without any specifics. It doesn't show my purpose, but it's the same issue.
elements: list = [] # List meant to contain a tuple with the name of the item and the function of the item.
def quit_code():
exit()
element.append(("quit", quit_code))
Now, somewhere else in the code, I want to be able to use an if statement to check the name of the item and, if it's the right one at that time, run the function.
user_input = "quit" # For brevity, I'm just writing this. Let's just imagine the user actually typed this.
if elements[0][0] == user_input:
#This is the part I don't understand so I'm just going to make up some syntax.
run_method(elements[0][1])
The method run_method that I arbitrarily made is the issue. I need a way to run the method returned by elements[0][1], which is the quit_code method. I don't need an alternative solution to this example because I just made it up to display what I want to do. If I have a function or object that contains a function, how can I run that function.
(In the most simplified way I can word it) If I have object_a (for me it's a tuple) that contains str_1 and fun_b, how can I run fun_b from the object.
To expand on this a little more, the reason I can't just directly call the function is because in my program, the function gets put into the tuple via user input and is created locally and then stored in the tuple.
__list_of_stuff: list = []
def add_to_list(name, function):
__list_of_stuff.append((name, function))
And then somewhere else
def example_init_method():
def stop_code():
exit()
add_to_list("QUIT", stop_code())
Now notice that I can't access the stop_code method anywhere else in the code unless I use it through the __list_of_stuff object.
Finally, It would be nice to not have to make a function for the input. By this, I mean directly inserting code into the parameter without creating a local function like stop_code. I don't know how to do this though.
Python treats functions as first-class citizens. As such, you can do things like:
def some_function():
# do something
pass
x = some_function
x()
Since you are storing functions and binding each function with a word (key), the best approach would be a dictionary. Your example could be like this:
def quit_code():
exit()
operations = dict(quit=quit_code)
operations['quit']()
A dictionary relates a value with a key. The only rule is the key must be immutable. That means numbers, strings, tuples and other immutable objects.
To create a dictionary, you can use { and }. And to get a value by its key, use [ and ]:
my_dictionary = { 'a' : 1, 'b' : 10 }
print(my_dictionary['a']) # It will print 1
You can also create a dictionary with dict, like so:
my_dictionary = dict(a=1, b=10)
However this only works for string keys.
But considering you are using quit_code to encapsulate the exit call, why not using exit directly?
operations = dict(quit=exit)
operations['quit']()
If dictionaries aren't an option, you could still use lists and tuples:
operations = [('quit',exit)]
for key, fun in operations:
if key == 'quit':
fun()

Why do I need a 'return' and a new variable?

I am a newbie in Python programming and I would like to understand better the logic of programming. The code below is intended to create a function that assigns its parameters to a dictionary, prompt the user about an artist and a title name, call the function back passing the arguments (given by the user) to the parameters and print the function (the dictionary).
def make_album(artist, album_name):
entry = {'name' : artist, 'album' : album_name}
return entry
while True:
print("\nPlease, write your fav artist and title: ")
print("\nType 'q' to quit.")
band_name = input('Artist name: ')
if band_name == 'q':
break
title_name = input('Title name: ')
if title_name == 'q':
break
comp_entry = make_album(band_name, title_name)
print(comp_entry)
The code runs perfectly. But there are two points that I can not understand:
Why do I need the 'return entry' line? The function creates a dictionary and it is done. Why a return?
Why do I need to create a variable in the end, assign the result of the function and print it? There is already a variable (entry) addressed as the dictionary! I would like to just write instead:
make_album(band_name, title_name):
print(entry)
I know, the code will not run, but I would be very happy with some words explaining me the reason of why these 2 points.
entry is defined inside the function, so it cannot be accessed outside of it.
Check this article about closures
http://www.trytoprogram.com/python-programming/python-closures/
What you have to understand is the concept of scope in python. This article is a good place to start.
You can directly print the value this way too
print(make_album(band_name, title_name))
The variable comp_entry is used to store the value returned from the make_album function. So, if you want a function to return back a value on calling the function, provide a return statement
It will print None if no return is provided.

How do I pass my list variable back outside of my function (Python)

I thought that using the return function would cause the variable placed after it to be passed outside of my function (returned?). It appears not, why not?
I am trying to write some code that requires me to compile a list of 5 items inside a function, and then pass that list outside of the function and do some work with it. Right now I only have a print statement written outside of it, just trying to see if it's getting passed outside of my function but ill need to do more later on. It is telling me variable is undefined so I am assuming that it is not getting passed.
Why would a list variable placed after the return command not be passed outside of the function and be free to use, and what do I need to do to make it so that I can in fact call my list variable outside of the function?
#Gather data about elements and turn into a list to check agsint function list later
!curl https://raw.githubusercontent.com/MicrosoftLearning/intropython/master/elements1_20.txt -o elements1_20.txt
elements_20 = open("elements1_20.txt","r")
elements_20.seek(0)
elements = elements_20.readline().strip()
element_list = []
while elements:
element_list.append(elements)
elements = elements_20.readline().strip()
print(element_list)
# define function to get user input and compile it into a list
def get_name():
user_list = []
while len(user_list) < 5:
user_input=input("Name one of the first 20 items please kind sir: ")
#check to make sure the input is unique
if user_input.lower() in user_list:
print("please don't enter the same word twice")
else:
user_list.append(user_input.lower())
return user_list
get_name()
print(user_list)
A side note I need the function to not take any arguments so I can't use that method as a solution.
You need to save the returned value from get_name() to a variable named user_list outside of the scope of the function in order to print it:
#Storing the returned value from the function:
user_list = get_name()
print(user_list)
Without storing the return value, the function completes itself, returns the value up the stack where it is captured by nothing, and then it is subsequently dereferenced. The assignment of user_list within the body of the function is only applicable inside of the scope of the function. As soon as it is returned, the program no longer 'sees' any variables named user_list, which causes the print() statement to fail.

Python Beginner Programming

I am still working on the same encryption program before and I am currently stuck.
choice = ""
def program (str,my_fn):
global i
i=0
while i<len(str):
my_fn
i += 1
def encrypt(my_result):
message.append(ord(answer[i]))
while choice != "Exit":
choice = input("Do you want to Encrypt, Decrypt, or Exit?\n")
if choice == "Encrypt":
answer = input("What would you like to encrypt:\n")
message = []
program(answer,encrypt(message))
print (answer)
print (message)
So the first part of the program is simply asking the user if they wish to Encrypt, Decrypt, or Exit the program, this part works perfectly fine. However, my issue is with the functions. Function "program" is intended to serve as a repeater for the inner function for every single letter in the string. However, when I try to run the program, it continues to tell me that "i" isn't defined for the "encrypt" function and does nothing. I am certain I set "i" as a global variable so why isn't this working. In case you are wondering why I chose to make two functions, it is because I will later have to use function "program" multiple time and for this specific assignment I am required to use functions and abstractions. Thanks!
Add one line after your first line
choice = ""
i = 0
The keyword global means you declare an access to a global name.
Also, using a global variable is almost never a good idea. You may want to find another way to design your function.
The line program(answer,encrypt(message)) doesn't do what you want it to do. Rather than passing the function encrypt and its argument message to program (which can call it later), it calls the function immediately. It would pass the return value to program instead, but since encrypt(message) doesn't work without i defined, you get an exception instead.
There are a few ways you could fix this. By far the best approach is to not use global variables in your functions, and instead always pass the objects you care about as arguments or return values.
For instance, you could pass a function that encrypts a single letter to another function that repeatedly applies the first one to a string (this would be very much like the builtin map function):
def my_map(function, string):
result = []
for character in string:
result.append(function(character))
return result
def my_encryption_func(character):
return ord(character)
If you really want to stick with your current architecture, you could make it work by using functools.partial to bind the answer argument to your encrypt function, and then call the partial object in program:
from functools import partial
def program (str,my_fn):
global i
i=0
while i<len(str):
my_fn() # call the passed "function"
i += 1
def encrypt(my_result):
message.append(ord(answer[i]))
choice = ""
while choice != "Exit":
choice = input("Do you want to Encrypt, Decrypt, or Exit?\n")
if choice == "Encrypt":
answer = input("What would you like to encrypt:\n")
message = []
program(answer, partial(encrypt, message)) # pass a partial object here!
print (answer)
print (message)

How can I make 'uName' display the correct name that the user inputs after clarifying checks?

I am very new to Python, as you can probably tell from the code. To begin, I am trying to have the user input their name and store that in a global variable that I can access all throughout my code...preferably named uName.
What's happening is during the loop cycle, it asks the user 'Is this your name?' after they input the first response. If I hit type anything but 'yes' or 'Yes', it will re-ask them to input the name. BUT, when they finally hit 'Yes', the program prints the very first name they entered.
Also, any tips on code structure or wording is helpful...
game.py
from decisions import *
import decisions
global globalname
globalname = ''
def gameEngine(uName):
looper = 0
while looper == 0:
print ('You said your name is, ') + uName + ('...')
clarifier = raw_input('Is that correct?\n')
if clarifier == 'yes' or clarifier == 'Yes':
namePrinter(answer)
else:
decisions.userDecisions(username)
def namePrinter(uName):
print uName
gameEngine(answer)
decisions.py
username = ''
def userDecisions(inputs):
response = raw_input("Please enter your name...\n>>> ")
return response
answer = userDecisions(username)
The specific issue that you are encountering is that you are first running the contents of decisions.py though the import statement in game.py. Through that, you have set the variable "answer" to be equal to the first name that the user inputs.
Then you are calling the gameEngine function in game.py, supplying the "answer" variable from decisions.py as the argument, which is stored in "uName". Upon the user entering another name the name is not stored anywhere and is thrown out with the following line.
decisions.userDecisions(username)
You can assign the return of that statement to a variable such as "uName", and that will get you closer to what you want to do.
uName = decisions.userDecisions(username)
The next issue is that when you are printing out the name, you are printing out the variable "answer" as opposed to "uName". This is what is mainly causing the issue of the first name always being printed out.
namePrinter(answer)
This could be resolved by passing in the "uName" variable instead.
namePrinter(uName)
Also if you want the final chosen name to be stored in the global variable you can assign the final user chosen name to the gloabl variable after the user confirms that the nameis correct.
globalname = uName
However, you may want to be careful about a few parts of the structure of your code.
First, you may want to try not to use global variables. Instead you should be passing around the name though the functions which use it. If you have other player information that you need to access often, you can create a Player class and object to store that information in a single object which can be passed around into functions as needed.
Second, as the userDecisions function does not use its arguement "inputs", you can remove that arguement, as it isn't used.
Third, you may want to be careful about running code through import statements alone. Generally when you are importing a source file, you should be importing the functions, and not rely upon imports to directly run code. For example you can remove the non-function lines of decisions.py and simply run the following in game.py instead.
gameEngine(decisions.userDecisions())
I reccomend that you look up some resources on functions and passing arguement in Python, as they might be able to explain the underlying concepts a bit better.
You have screwed up with the variables and their scope. Read more about them here.
To give you a perspective regarding the scope of variables concisely, look at this code snippet:
# This is a global variable
a = 0
if a == 0:
# This is still a global variable
b = 1
def my_function(c):
# this is a local variable
d = 3
print(c)
print(d)
# Now we call the function, passing the value 7 as the first and only parameter
my_function(7)
# a and b still exist
print(a)
print(b)
# c and d don't exist anymore -- these statements will give us name errors!
print(c)
print(d)
Regarding your code, you may want to have a look at these issues:
The answer variable is not accessible in the game.py module.
So is the case with username variable in the decisions.userDecisions(username) call.
The decisions.userDecisions(username) call in the gameEngine(uName) method is not storing the response to any variable and hence the response will be lost.
You are declaring global variable globalname but not assigning any value to it (of course other than '').
P.S.: I was tempted to do your homework for you, but then probably this is good enough information for you to learn more. ;)

Categories

Resources