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.
Related
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
So I am working on doing a "simple" task since like 2h and still can't find the solution, so where is my question :
I want to search in a file, line by line, and if no result is found, at the end print something, else call a function.
def DeletItemCheckUp():
import re
find = True
itemNumber = input("\n what is the item you want to delet : ")
fileItem = open('Data_Item', 'r', encoding='Utf-8')
for line in fileItem:
sr = re.search(r'^\b%s\b'%itemNumber,(line.split(';')[0]))
if (sr == None):
pass
print("This item don't exist.")
fileItem.close()
if (find == True):
return itemNumber
DeletItem()
so here is the problem I have got with different try :
1. Print "This item don't exist." for every line that didn't had my itemNumber.
2. When there was actually no match found, its would not call DeletItem().
objectif of the code :
Ask for a item to delet, check in a file if the unique item number exist, if so, call DeletItem() to delet it, else, tell the user that this unique item number don't exist.
Few overlooks in there to achieve what you ask. We are going to use a flag (true/false) to know when we found something, and based on that we will decide whether to call the function or print/return the number.
def DeletItemCheckUp():
import re
find = False # initialize to False
itemNumber = input("\n what is the item you want to delet : ")
fileItem = open('Data_Item', 'r', encoding='Utf-8')
for line in fileItem:
sr = re.search(r'^\b%s\b'%itemNumber,(line.split(';')[0]))
if (sr == None):
continue # do nothing and continue
else:
# we found the number, set the flag and break
find = True
break # no need to continue searching
fileItem.close()
if (find):
DeletItem() # call the function
else:
print("This item don't exist.")
1) replace the pass with your print('This item doesn't exist'). "Pass" means "do nothing."
2) Your DeleteItem() is after the return. Nothing executes after the return because you have returned to the place the function was called from. You want
else:
DeleteItem()
I have a program that maintains a flat file database of cd information. I am trying to write a function that updates the database. In this function I am checking to see if the artist exists and if so, appending the album name to this artist, but for some reason it will not see that the artist I type in already exists. I made sure that I type it in exactly like it is in the dictionary but for some reason python will not see that it is there. Why would this be happening? I have included sample input as well as the python program. Any help would be greatly appreciated.
import sys
def add(data, block):
artist = block[0]
album = block[1]
songs = block[2:]
if artist in data:
data[artist][album] = songs
else:
data[artist] = {album: songs}
return data
def parseData():
global data
file='testdata.txt'
data = {}
with open(file) as f:
block = []
for line in f:
line = line.strip()
if line == '':
data = add(data, block)
block = []
else:
block.append(line)
data = add(data, block)
return data
def artistQry():
global artists, usrChoiceArt, albums, usrChoiceAlb, usrArtist
artists=sorted(data.keys())
for i in range(0,len(artists)) :
print str(i+1) + " : " + artists[i]
usrChoiceArt = raw_input("Please choose an artist or enter q to quit:")
if usrChoiceArt=='q' :
print "Quitting Now"
exit()
else :
albumQry()
def albumQry():
global artists, usrChoiceArt, albums, usrChoiceAlb, usrArtist
usrArtist=artists[int(usrChoiceArt)-1]
albums=sorted(data[usrArtist].keys())
for i in range(0,len(albums)) :
print str(i+1) + " : " + albums[i]
usrChoiceAlb=raw_input("Please choose an album or enter a to go back:")
if usrChoiceAlb=="a":
artistQry()
else:
trackQry()
def trackQry():
global artists, usrChoiceArt, albums, usrChoiceAlb, usrArtist
usrAlbum=albums[int(usrChoiceAlb)-1]
tracks=data[usrArtist][usrAlbum]
for i in range(0,len(tracks)) :
print tracks[i]
usrChoiceTrack=raw_input("Enter \"a\" to go back or \"q\" to quit:")
if usrChoiceAlb=="q":
print "Quitting Now"
exit()
elif usrChoiceTrack=="a":
albumQry()
else:
print "Invalid Choice"
trackQry()
def artistExist(Name):
for i in range(0,len(data.keys())):
if Name==data.keys()[i]:
return True
else:
return False
def updData():
artistName=raw_input("Please enter an artist name:")
albumName=raw_input("Please enter an album name:")
trackList=raw_input("Please enter the track list seperated by comma's:")
if artistExist(artistName):
data[artistName].append(albumName)
print data[artistName]
elif not artistExist(artistName):
print "Quitting"
exit()
if __name__ == '__main__':
data = parseData()
if sys.argv[1]=='-l':
artistQry()
elif sys.argv[1]=='-a':
updData()
Input data:
Bob Dylan
1966 Blonde on Blonde
-Rainy Day Women #12 & 35
-Pledging My Time
-Visions of Johanna
-One of Us Must Know (Sooner or Later)
-I Want You
-Stuck Inside of Mobile with the Memphis Blues Again
-Leopard-Skin Pill-Box Hat
-Just Like a Woman
-Most Likely You Go Your Way (And I'll Go Mine)
-Temporary Like Achilles
-Absolutely Sweet Marie
-4th Time Around
-Obviously 5 Believers
-Sad Eyed Lady of the Lowlands
In your function artistExist, you return False on the very first iteration! Instead, you must wait until all iterations are finished.
for i in range(0,len(data.keys())):
if Name==data.keys()[i]:
return True
return False
In addition to what Padraic Cunningham says below, the elif here is also redundant:
if artistExist(artistName):
...
elif not artistExist(artistName):
...
If something isn't True, then it can only be False. So really you should just have
if artistExist(artistName):
...
else:
...
And since the function is just a needless one-liner, an even better expression is
if artistName in data:
...
else:
...
Apart from returning too early by returning False in the loop you are doing way too much work, you simply need to use return Name in data:
def artistExist(Name):
return Name in data # will return True or False with O(1) lookup
Every time you call .keys you are creating a list in python2 so your lookup is actually quadratic in the worst case as opposed to 0(1) with the simple return Name in data. A big part of using a dict is efficient lookups which you lose calling .keys. If you actually wanted to iterate over the keys you would simply for key in data, no call to .keys and no need for range.
I've just undertaken my first proper project with Python, a code snippet storing program.
To do this I need to first write, then read, multiple lines to a .txt file. I've done quite a bit of googling and found a few things about writing to the file (which didn't really work). What I have currently got working is a function that reads each line of a multiline input and writes it into a list before writing it into a file. I had thought that I would just be able to read that from the text file and add each line into a list then print each line separately using a while loop, which unfortunately didn't work.
After going and doing more research I decided to ask here. This is the code I have currently:
'''
Project created to store useful code snippets, prehaps one day it will evolve
into something goregous, but, for now it's just a simple archiver/library
'''
#!/usr/local/bin/python
import sys, os, curses
os.system("clear")
Menu ="""
#----------- Main Menu ---------#
# 1. Create or edit a snippet #
# 2. Read a snippet #
# 0. Quit #
#-------------------------------#
\n
"""
CreateMenu ="""
#-------------- Creation and deletion --------------#
# 1. Create a snippet #
# 2. Edit a snippet #
# 3. Delete a snippet (Will ask for validation) #
# 0. Go back #
#---------------------------------------------------#
\n
"""
ReadMenu="""
#------ Read a snippet ------#
# 1. Enter Snippet name #
# 2. List alphabetically #
# 3. Extra #
# 0. Go Back #
#----------------------------#
"""
def readFileLoop(usrChoice, directory):
count = 0
if usrChoice == 'y' or 'n':
if usrChoice == 'y':
f = open(directory, 'r')
text = f.read()
f.close()
length = len(text)
print text
print length
raw_input('Enter to continue')
readMenu()
f.close()
elif choice == 'n':
readMenu()
def raw_lines(prompt=''):
result = []
getmore = True
while getmore:
line = raw_input(prompt)
if len(line) > 0:
result.append(line)
else:
getmore = False
result = str(result)
result.replace('[','').replace(']','')
return result
def mainMenu():
os.system("clear")
print Menu
choice = ''
choice = raw_input('--: ')
createLoop = True
if choice == '1':
return creationMenu()
elif choice == '2':
readMenu()
elif choice == '0':
os.system("clear")
sys.exit(0)
def create():
os.system("clear")
name = raw_input("Enter the file name: ")
dire = ('shelf/'+name+'.txt')
if os.path.exists(dire):
while os.path.exists(dire):
os.system("clear")
print("This snippet already exists")
name = raw_input("Enter a different name: ")
dire = ('shelf/'+name+'.txt')
print("File created\n")
f = open(dire, "w")
print("---------Paste code below---------\n")
text = raw_lines()
raw_input('\nEnter to write to file')
f.writelines(text)
f.close()
raw_input('\nSnippet successfully filled, enter to continue')
else:
print("File created")
f = open(dire, "w")
print("---------Paste code below---------\n")
text = raw_lines()
print text
raw_input('\nEnter to write to file')
f.writelines(text)
f.close()
raw_input('\nSnippet successfully filled, enter to continue')
def readMenu():
os.system("clear")
name = ''
dire = ''
print ReadMenu
choice = raw_input('--:')
if choice == '1':
os.system("clear")
name = raw_input ('Enter Snippet name: ')
dire = ('shelf/'+name+'.txt')
if os.path.exists(dire):
choice = ''
choice = raw_input('The Snippet exists! Open? (y/n)')
'''if not choice == 'y' or 'n':
while (choice != 'y') or (choice != 'n'):
choice = raw_input('Enter \'y\' or \'n\' to continue: ')
if choice == 'y' or 'n':
break'''
readFileLoop(choice, dire)
else:
raw_input('No snippet with that name exists. Enter to continue: ') #add options to retry, create snippet or go back
readMenu()
elif choice == '0':
os.system("clear")
print Menu
def creationMenu(): ###### Menu to create, edit and delete a snippet ######
os.system("clear")
print CreateMenu
choice = raw_input('--: ')
if choice == '1': ### Create a snippet
os.system("clear")
print create()
print creationMenu()
elif choice == '2':
os.system("clear") ### Edit a snippet
print ("teh editon staton")
raw_input()
print creationMenu()
elif choice == '3':
os.system("clear") ### Delete a snippet
print ("Deletion staton")
raw_input()
print creationMenu()
elif choice == '0': ### Go Back
os.system("clear")
######## Main loop #######
running = True
print ('Welcome to the code library, please don\'t disturb other readers!\n\n')
while running:
mainMenu()
######## Main loop #######
Tl;Dr: Need to write and read multiline text files
The problem that I'm having is the way the multilines are being stored to the file, it's stored in list format e.g ['line1', 'line2', 'line3'] which is making it difficult to read as multilines because I can't get it to be read as a list, when I tried it added the whole stored string into one list item. I don't know if I'm writing to the file correctly.
OK, so the problem is with writing the file. You're reading it in correctly, it just doesn't have the data you want. And the problem is in your raw_lines function. First it assembles a list of lines in the result variable, which is good. Then it does this:
result = str(result)
result.replace('[','').replace(']','')
There are two small problems and one big one here.
First, replace:
Return[s] a copy of the string with all occurrences of substring old replaced by new.
Python strings are immutable. None of their methods change them in-place; all of them return a new string instead. You're not doing anything with that new string, so that line has no effect.
Second, if you want to join a sequence of strings into a string, you don't do that by calling str on the sequence and then trying to parse it. That's what the join method is for. For example, if your lines already end with newlines, you want ''.join(result). If not, you want something like '\n'.join(result) + '\n'. What you're doing has all kinds of problems—you forgot to remove the extra commas, you will remove any brackets (or commas, once you fix that) within the strings themselves, etc.
Finally, you shouldn't be doing this in the first place. You want to return something that can be passed to writelines, which:
Write[s] a sequence of strings to the file. The sequence can be any iterable object producing strings, typically a list of strings.
You have a list of strings, which is exactly what writelines wants. Don't try to join them up into one string. If you do, it will run, but it won't do the right thing (because a string is, itself, a sequence of 1-character strings).
So, if you just remove those two lines entirely, your code will almost work.
But there's one last problem: raw_input:
… reads a line from input, converts it to a string (stripping a trailing newline), and returns that.
But writelines:
… does not add line separators.
So, you'll end up with all of your lines concatenated together. You need the newlines, but raw_input throws them away. So, you have to add them back on. You can fix this with a simple one-line change:
result.append(line + '\n')
To read multiple lines from a file, it's easiest to use readlines(), which will return a list of all lines in the file. To read the file use:
with open(directory, 'r') as f:
lines = f.readlines()
And to write out your changes, use:
with open(directory, 'w') as f:
f.writelines(lines)
fileList = [line for line in open("file.txt")]
While the previously mention idiom will work for reading files, I like mine. Its short and to the point.
I'm writing a function that prompts for input and then returns different results based on the input and then asks for input again. I've got it returning the correct values, but I'm not sure how to make it prompt for input again.
Here's the actual code of the function:
def interact():
command = raw_input('Command:')
command = command.split(' ')
if command[0] == 'i':
bike_name = command[1] + ' ' + command[2]
return get_product_id(products, bike_name)
if command [0] == 'n':
return get_product_name(products, command[1])
if command[0] == 'c':
return compute_cost(products, part, command[1])
if command[0] == 'p':
return get_parts(products, command[1])
In each line with return in it, it is simply calling up a previously defined function. The products and part are dictionaries, defined previously.
I can only use the builtin functions.
I would do it with a while loop. Like This:
while True:
com = raw_input('Command:').split()
if len(com) == 0:
break
elif com[0] == 'i':
bike_name = command[1] + ' ' + command[2]
return get_product_id(products, bike_name)
You've done most of the work, you just need this:
while True:
print interact()
There is no need to take so much pain and write your own command line interpreter.
Look at this: http://docs.python.org/2/library/cmd.html
One way is to put it in a while loop, and then also check for an exit input to break out.
Call the method inside an (end-less) loop:
while True:
some_method()