so far I have this:
import datetime
f = open("log.txt", "a", encoding='UTF-8')
print ("Log file created")
print ("Enter /close to leave.")
spc = " "
while 1:
msg = input(">>:")
now = datetime.datetime.now()
now1 = str(now)
if msg == None:
pass
if msg == " ":
pass
else:
msg2 = now1+spc+msg+"\n"
if msg == "/close":
exit()
f.write(msg2)
f.flush()
However, this line is not functioning as I want it, it still returns a blank line on the log file:
if msg == None:
pass
I want it to not return anything and simply continue the while loop, How would I fix this?
You should be using
if msg is None:
pass
Edit
You're missing what the pass function is all about. I would re-write your look like so. This way we're only processing this if the msg is not one of the bad input. Once we're done we break out of the loop.
...
while 1:
msg = input(">>:")
now = datetime.datetime.now()
now1 = str(now)
if not msg in [None, " "]
msg2 = now1+spc+msg+"\n"
if msg == "/close":
exit()
f.write(msg2)
f.flush()
break
Evaluation of the rest of the loop will still continue after pass, and as None does not equal " ", this means the block beginning with msg2 = now1+spc+msg+"\n" will be executed. You need to either unite the if ... if ... else into a single if block by changing if msg == " ": to elif msg == " ": or else change if msg == None: pass to if msg == None: continue.
try:
msg2 = now1+spc+msg+"\n"
if msg == "/close":
exit()
f.write(msg2)
f.flush()
except:
pass #example for a function: return None or raise
Your condition doesn't make any sense. The input function will never return None, only strings.
If you want to skip empty strings, a better test would be if not msg (empty strings are "falsy"). Or, if you want to reject any all-whitespace strings, try if not msg.strip() (which removes leading and trailing whitespace before checking if the rest of the string is empty or not).
Further, it's rarely a good idea to write an if statement that just contains pass. Instead, invert the test so that the condition is true for cases where you want to run some code (in this case, when msg is not empty or all whitespace) and simply omit the cases where you'd do nothing:
while 1:
msg = input(">>:")
now = datetime.datetime.now()
now1 = str(now)
if msg.strip(): # msg is not empty or all whitespace
msg2 = now1+spc+msg+"\n"
if msg == "/close":
exit()
f.write(msg2)
f.flush()
One final issue (unrelated to the main question). Python's exit function is primarily intended for use in the interactive interpreter. It is added to the builtins by the site module, and so it won't exist if Python was run with the -S flag. If you want to close the interpreter, you should instead call sys.exit, raise a SystemExit exception, or just run off the end of the main module (a break statement would probably do that for the loop you've shown here, or perhaps a return if you're in a function somewhere).
Related
In the case I am looping into a list, where for value msg_list = 0 it will execute action(0), usr). This action can fail for a determined user, I should choose aother user if it happens, perform all the actions related to the user
How can I do to repeat action[0] if it fails?
for msg in range(len(msg_list)):
# in this case msg = 0
usr = select_random_user()
multiple_actions_for(usr) # This are lots of code lines I don't want to repeat!!
try:
action(msg, usr)
more_actions(usr.related_stuff)
except Exception as e:
go_back_to(msg =0 instead of looping into msg=1) # this is what I want to do
How can I do to get that? Repeat the loop for msg = i instead of passing to msg = i + 1?
Put your code into the endless while-loop with exiting from it if try was successful:
for msg in range(len(msg_list)):
while True:
usr = select_random_user()
multiple_actions_for(usr)
try:
action(msg, usr)
more_actions(usr.related_stuff)
except Exception as e:
continue
else:
break
It really depends. Is it okay to go back to the beginning of the loop? If so, you can call "continue", which stops the current iteration, and restarts the loop. Otherwise, I don't think there's something similar to a goto in Python, no. It's a very structured language.
Try using while loop instead of for loop. The idea is as shown bellow:
bool still_looping = True
msg = 0
while still_looping:
usr = select_random_user()
multiple_actions_for(usr)
try:
action(msg, usr)
more_actions(usr.related_stuff)
if (msg < len (msg_list)):
msg += 1
except Exception as e:
# Do whatever you want here. msg was not incremented
if (msg == len(msg_list))
still_looping = False #verify if this was the last execution
I'm trying to make sure the input the user uses is all letters.I tried the .alpha method but since this is a file, a "." will be included returning it false. I also tried using "quit" sentinel value to exit the program but that isn't working. It keeps saying break is outside the loop. I also want the user to keep inputting if the file is not found error is raised.
The Assignment1
def main():
fileName = inputTxt()
FiletoReadFrom = openingFile(fileName)
counter = 0
for line in FiletoReadFrom:
outputFile = open("output.txt", "a+")
counter = counter + 1
outputFile.write("/* {} */ {}\n".format(counter, line.strip()))
if counter == 0:
print("This is an empty file")
else:
print("The file has been made")
FiletoReadFrom.close()
outputFile.close()
def inputTxt():
flag = True
while flag == True:
FileName= input("Please Enter the Name of the File, or type quit to exit ")
if FileName == quit:
flag == False
break
print("goodbye")
else:
return FileName
def openingFile(filetoReadFrom):
try:
a = open(filetoReadFrom, 'r')
return a
except FileNotFoundError:
print("This File was not Found", "Enter again or type quit to exit")
main()
There are different questions here, which is frowned upon on this site. Please never do that again.
the quit and break problem:
It is just a typo. As you forgot quoting 'quit', Python sees it at an undeclared variable which gives a syntax error. Fix:
...
while flag == True:
FileName= input("Please Enter the Name of the File, or type quit to exit ")
if FileName == 'quit':
flag == False
break
...
But it is still wrong, because break will only exit from the loop and inputTxt will return None which is not what you expect. Calling sys.exit() could be better here.
Test for letters and not numbers:
You must choose a white list (only alphas and dot) or black list (no numbers) way. In idiomatic Python it could be:
if all((x.isalpha() or x == '.') for x in FileName): # white list
# process error condition
if any(x.isdigit() for x in FileName): # black list
# process error condition
You could also use the re module which is great at controlling that a string respect a given pattern...
keep asking until a valid file is given:
You should use a loop:
def main():
while True:
fileName = inputTxt()
FiletoReadFrom = openingFile(fileName)
if FileToReadFrom is not None: # openingFile returns None when file does not exist
break
But IMHO, you should remove the openingFile function and directly use (and test) open in main
Is there a keyword that I can use to iterate a for loop without stepping the iterator? I know that it's possible to do this without such a command, by using a while loop and iterating manually, but it would greatly simplify things, in this instance, if I could just use a for loop, since continuing without iteration is the exception, not the rule. (there will significantly more conditions added to this when it is complete, all of which will require iteration). Here's my code (or, what I've written so far):
for line in file_as_list:
response = input(line)
if response.lower() == 'help':
self.show_command_list()
response = input(line)
if response.lower() == 'loc':
self.show_location(file_as_list, location)
response = input(line)
if response.lower() == 'exit':
save_changes = input('Would you like to save the changes you have made? (Y/N) ')
while (save_changes.upper() != 'Y') & (save_changes.upper() != 'N'):
save_changes = input('That is not a valid response. Try again. ')
if save_changes.upper() == 'N':
temp = file_as_list
print('Changes were not saved.')
else:
for line in file_as_list[location:]:
temp.append(line)
print('Changes were saved.')
break
if response.lower() == 'inline':
line += ' //' + input(line + ' //')
print('Line generated: ' + line)
location += 1
temp.append(line)
I think you want two nested loops. Try something like this:
for line in file_as_list: # outer loop
while True: # inner loop
response = input(line).lower()
if response == 'help': # these two options don't exit the inner loop
...
elif response == 'loc': # so they won't consume a line from the for loop
...
else:
break
if response == 'exit': # these other two conditions are outside the while loop
...
elif response == 'inline': # so a new line will be fetched after they run
...
If either of the first two conditions are met, the inner loop will keep on running without changing line. Only if the break gets hit will the inner loop end, and the other conditions get tested. After they do their thing, a new value will be assigned to line, as the for loop continues iterating.
Unrelated to your main question, I also changed the input line to call lower on the input immediately before saving it to response. That means the conditions don't need to keep calling it repeatedly. Your code isn't wrong there, but if you never care about the user's capitalization, throwing it away right off the bat can simplify things.
You can use an explicit iterator like
it = iter(file_as_list)
for line in it:
input(line)
...
input(next(it))
and so on. Just be sure to properly handle the case where you run out of lines!
You have two types of commands: ones that advance the iterator, and ones that don't. You could also call it action vs descriptive commands. Your best bet conceptually is to have a while loop that will continue to seek input until you get an action command. This while loop will live inside the existing for loop.
The advantage of this is that currently, your descriptive commands like "help" and "loc" can't be repeated, but you probably want them to be.
Another decision I would recommend is to use distinct functions to implement each command. By giving the commands a consistent interface, you make the code easier to maintain and understand. By registering the commands in a dictionary, you can make your lookup faster and more flexible.
The following concept has a bunch of functions that return a tri-state boolean value and an update. The boolean is True if the command wants to stay on the current line, False to continue. None to exit. The line update is usually just the input.
# in __init__
...
self.command_map = {
'help': self.help,
'loc': , self.loc,
'exit': self.exit,
'inline': self.inline,
}
self.temp = []
...
def help(self, file_as_list, location, line):
self.show_command_list()
return True, line
def loc(self, file_as_list, location, line):
self.show_location(file_as_list, location)
return True, line
def exit(self, file_as_list, location, line):
save_changes = ''
while len(save_changes) != 1 or save_changes.upper() not in 'YN':
save_changes = input('Would you like to save the changes you have made? (Y/N) ')
if save_changes.upper() == 'N':
self.temp = file_as_list
print('Changes were not saved.')
else:
self.temp.extend(file_as_list[location:])
print('Changes were saved.')
return None, line
def inline(self, file_as_list, location, line):
line += ' //' + input(line + ' //')
print('Line generated: ' + line)
return True, line
def process(self):
for location, line in enumerate(file_as_list):
stay = True
while stay:
response = input(line)
command = command_map.get(response.casefold())
if command is None:
print(f'Command "{response}" not found. Try again')
else:
stay, line = command(file_as_list, location, line)
if stay is None:
break
self.temp.append(line)
Given command_map, you can do lots of things easier: for example, you can reimplement show_command_list to do something with sorted(command_map.keys()). I'm sure you can see how relatively easy it is to add commands to your list. You don't have to repeat boilerplate code, just be careful with the inputs and return values.
This construction is also much easier to iterate manually if you don't like the idea of having nested loops:
def process(self):
stay = False
iterator = enumerate(file_as_list)
while True:
if not stay:
try:
location, line = next(iterator)
except StopIteration:
break
response = input(line)
command = command_map.get(response.casefold())
if command is None:
print(f'Command "{response}" not found. Try again')
stay = True
else:
stay, line = command(file_as_list, location, line)
if stay is None:
break
if not stay:
self.temp.append(line)
As you can see, this method requires quite a bit more special handling for the various conditions.
I have Python code like:
x = sys.argv[1]
y = sys.argv[2]
i = sofe_def(x,y)
if i == 0:
print "ERROR"
elif i == 1:
return str(some_var1)
else:
print "OOOps"
num = input("Chose beetwen {0} and {1}".format(some_var2, some_var3))
return str(num)
After I must execute this script in shell script and return string in shell variable, like:
VAR1="foo"
VAR2="bar"
RES=$(python test.py $VAR1 $VAR2)
Unfortunately it doesn't work. The way by stderr, stdout and stdin also doesn't work due to a lot of print and input() in code. So how I can resolve my issue? Thank you for answer
That isn't even valid Python code; you are using return outside of a function. You don't wan't return here, just a print statement.
x, y = sys.argv[1:3]
i = sofe_def(x,y)
if i == 0:
print >>sys.stderr, "ERROR"
elif i == 1:
print str(some_var1)
else:
print >>sys.stderr, "OOOps"
print >>sys.stderr, "Choose between {0} and {1}".format(some_var2, some_var3)
num = raw_input()
print num
(Note some other changes:
Write your error messages to standard error, to avoid them being captured as well.
Use raw_input, not input, in Python 2.
)
Then your shell
VAR1="foo"
VAR2="bar"
RES=$(python test.py "$VAR1" "$VAR2")
should work. Unless you have a good reason not to, always quote parameter expansions.
Just use print instead of return - you bash snippet expects result on STDOUT.
Is there any pythonic way to deal with wrong user input? I'm creating a module to help people work with files, and I have functions like rename, move, basepath, etc. Example:
def move(file_path):
# do something and return
I would like to know how to handle exceptions (i.e. if I should wrap my code in a try-except block);
def move(file_path):
try:
# do something and return
except Exception as error:
# return error
If I should use the try-except, I would like to know how I should return from it. I have a background in functional programming, so I was thinking like this:
def move(file_path):
try:
# do something
return (True, something...)
except Exception as error:
return (False, error)
Other example:
def execute_query(database_cursor, query, fetch):
if type(database_cursor) != "":
return (1, "database_cursor isn't a valid database cursor")
cursor.execute(query)
if fetch == "*":
return self.cursor.fetchall()
yield self.cursor.fetchone()
In this case, I'm worried about the user sending input that is not a database.
Is there any convention for this functionality?
Thanks!
Update
How i'm doing:
from sys import exit
def testing_something(a, b, c):
try:
return 0, a + b + c
except Exception, error:
return 1, error
error, result = testing_something(1, 2, 3)
if error:
print error # raise error or treat.
sys.exit(error)
I think is very clever to do like this, now i can decide to raise it or to treat it.
In the past, I've used something like the following to ensure that a certain user input was "valid" in the sense that it was contained within a list or something. This was useful for validating manual file input for loading data into memory.
def validate_choice(selection, choices):
while selection not in choices:
selection = input("'%s' is not a valid entry. Try again: " % selection)
print("'%s' works! Returning..." % selection)
return selection
result1 = validate_choice('foo', ['foo', 'bar', 'baz'])
result2 = validate_choice('boogers', ['foo', 'bar', 'baz'])
If you're trying to coerce something of one type to another type, here's another example which coerces the user to enter either A) an integer or B) a number that can be coerced to an integer:
def str_to_int_validation(num):
parsed = False
while not parsed:
try:
num = input("Enter an integer: ")
num = int(num)
parsed = True
except ValueError:
print("'%s' is not an integer. Try again.")
return num
Hope that helps!
This you may consider Pythonic if you want, but it is nothing really but a hacky bit of code:
import os
import shutil
class MoveError(Exception): pass
def move (patha, pathb):
# Some checks
if not os.path.exists(patha):
return MoveError("'%s' does not exist!" % patha)
if os.path.exists(pathb):
return MoveError("'%s' already exists! I will not overwrite it!" % pathb)
print "Moving '%s' to '%s'..." % (patha, pathb)
try: shutil.move(patha, pathb)
except Exception, e:
return MoveError("Whoops, something nasty happened! Error is:\n%s" % str(e))
return "%i bytes moved" % os.path.getsize(pathb)
def help ():
print "This is some help!"
def quit ():
global running
print "Quitting!"
running = 0
commands = {"mv": move, "move": move, "help": help, "?": help, "q": quit, "quit": quit}
running = 1
while running:
inp = raw_input("--> ").split()
if not inp: continue
try: cmd = commands[inp[0]]
except:
print "Invalid command '%s'" % inp[0]
continue
result = cmd(*inp[1:])
if isinstance(result, Exception):
print "Error occurred!"
else: print "Done!"
if result is not None:
print result
Getting the command from commands dictionary could have also been:
cmd = commands.get(inp[0], None)
if not cmd: print "Command doesn't exist!"
or unefficient way:
if inp[0]not in commands:
print "No such command"
else: cmd = commands[inp[0]]
Now, we can start arguing over which of the three is more Pythonic. And that's just for this part of code.
But, it is dead true that returning exceptions, although it may be tempting is something to be done rarely. Usually only when you have to push something into some library's object to force it to catch the exception. (depends on design of the lib - and is very rarely needed). Your original design, starts well, with flag indicating error, but the second thing should be the error message then. Or go on like this, if you feel that you really need it for some reason. But you can always do:
def move (pa, pb):
raise MoveError, "I will not move anything!"
and then:
try:
commands["move"]("somefile", "somewhereelse") # To simulate call from user input
print "Done!"
except Exception, e:
print "An error occurred.\n%s" % str(e)