I made a program that can modify a list using commands that the user enters.
The commands that are supported are (used from actual program):
/add [value1] [value2] [valueN]...
- Add a value to the list/rvalue [value]
- Removes a value from the list/rindex [index]
- Removes the value at the specified index from the list/print
- Prints the list/help
- Lists every available command
Here is the code:
#Program to modify lists
value_list = []
def cmd_help():
print("/add [value1] [value2] [valueN]... - Add a value to the list")
print("/rvalue [value] - Removes a value from the list")
print("/rindex [index] - Removes the value at the specified index from the list")
print("/print - Prints the list")
print("/help - Lists every available command")
def get_command_params():
commands = {
"/add": lambda *value : value_list.extend(list(value)),
"/rvalue": lambda value : value_list.remove(value),
"/rindex": lambda value : value_list.pop(int(value)),
"/print": lambda : print(value_list),
"/help": cmd_help
}
while True:
input_cmd = input("Enter a command: ")
#Separate arguments
command = ""
current_args_index = -1
args = []
last_char = ""
for char in input_cmd:
#Update separator
if char == "/" or char == " ":
last_char = char
if last_char == "/":
command += char
elif last_char == "append":
args[current_args_index] += char
elif last_char == " ":
args.append("")
#To append individual characters to same index
last_char = "append"
++current_args_index
cmd = commands.get(command)
if cmd == None:
print("Invalid command!")
continue
return cmd, args
def main():
cmd_help()
#Wait for command
while True:
command, args = get_command_params()
#Execute command with arguments
try:
command(*args)
#Don't print success if command is print/help
if args != []:
print("Success!")
except IndexError:
print("Index out of range!")
except ValueError:
print("Element not found!")
except TypeError:
print("Invalid arguments! Type /help for help")
if __name__ == "__main__":
main()
1 Answer 1
value_list = []
Global variables are almost never necessary. If you are tempted to use a global, you have two choices:
- Give the variable as an argument and reassign it to what the function returns (or just give it if the function mutates it).
- Define a class and use instance attributes.
In this case, value_list
is used by far too many things and with lambda
functions and everything. Therefore, I would suggest that you define a Commands
class.
"/add": lambda *value : value_list.extend(list(value))
You don't need to convert value
to a list. That is just unnecessary processing time. A list can be extended by a list, a tuple, a string, a generator, ... whatever iterable you want.
"/rindex": lambda value : value_list.pop(int(value)),
I wouldn't convert it to an integer within a lambda
function. I would create a whole function that uses a try
block in case the user doesn't type a valid number. That is also helpful if the user does type a number, but types a number that is too big or too small.
elif last_char == "append" ... last_char = "append"
Don't use magic numbers (or magic values). You should define a constant called APPEND
that can really be assigned to any object except a single-character string.
++current_args_index
Python doesn't use ++
. If x
is 4
, then +x
is 4
and ++x
is still 4
. If x
is -4
, then +x
is -4
and ++x
is still -4
. In other words, it does absolutely nothing. Python isn't like C where that increments current_args_index
. If you want to increment it, do current_args_index += 1
cmd = ... if cmd == None: ...
I have two problems. First, if you treat None
as a special case, you can simply use a try
block. Second, you should say is None
, not == None
because a class could define its __eq__
method to say that any instance is equal to None
, but only None
really is None
.
Your main()
function and how you use it looks terrific! You take care of each error separately, and you don't call main()
unless your file is being run as a program. Keep it up!