Python for loop scope - python

I'm trying to format a dictionary variable to use as a report. I want to recurse through the dictionary and concatenate the items from the dictionary into a formatted string that will be printed/emailed out to users. I'm having issues getting with the string variable (text) losing some of the text concatenated to it.
What I want is:
first \n
\t status: first did not have any updates to apply \n
second \n
\t status: first did not have any updates to apply \n
My function is:
def formatReport(report, text = ""):
for x in report:
if isinstance(report[x], dict):
text += "{0} \n".format(x)
formatReport(report[x], text)
else:
text += "\t{0}: {1} \n".format(x, report[x])
return text
When I call:
report = {'first': {'status': 'first did not have any updates to apply'}, 'second': {'status': 'second did not have any updates to apply'}}
formatReport(report)
I get (note the order of the output is not important to me):
'second \nfirst \n'
After adding a ton of debugging:
def formatReport(report, text = ""):
for x in report:
print "before if: " + text
if isinstance(report[x], dict):
text += "{0} \n".format(x)
print "if: " + text
formatReport(report[x], text)
else:
text += "\t{0} : {1} \n".format(x, report[x])
print "else: " + text
return text
I have narrowed the issue to down to the fact that the text variable is losing the string appended after the else. ie on this line:
text += "\t{0} : {1} \n".format(x, report[x])
So the output of the debugging code after the else is run the first time in the first for loop looks like:
else: second
status : first did not have any updates to apply
When it loops back to the top of the for loop is looks like:
before if: second
From what I have read for loops and if/else statements do not have their own scope as Python does not have block level scoping. I'm at a lose here I have tried all kinds of different combinations or variable names, parameters, etc.... It's worth noting I want to run this code on dictionaries that are 3+ levels deep, hence the need for the recursive call in the if statement.

Related

Python \n gives two spaces in between output and \t gives one

I do not understand why when inputing a space between the code with \t gives one space of line between the 'green' and 'Some things I learned so far:' output. When I use \n it gives two spaces inbetween. Shouldn't the space be the same for either \t and \n? I know that \t does tab and \n is new line. but I do not understand how \n does two spaces inbetween
Code is:
fav_num = {
'rachel':'blue',
'hannah':'green',
}
print(fav_num['rachel'])
print(fav_num['hannah'])
#6-3
coding_glossary = {
'list':'mutable type where you can store info',
'tuple':'immutable type similar to list',
'string':'simple line of code'
}
print('\t')
print('Some things I learned so far: \n')
print('What a list is:')
print(coding_glossary['list'])
Output is :
blue
green
Some things I learned so far:
What a list is:
mutable type where you can store info
Process finished with exit code 0
python's built-in print function has '\n' as end character implicitly.
print(*objects, sep=' ', end='\n', file=sys.stdout, flush=False):
Print objects to the text stream file, separated by sep and followed by end. sep, end, file and flush, if present, must be given as keyword arguments
So, every time you run print() there is a '\n' character that gets printed implicitly unless you override the behavior by passing end= to it. (like end='' for instance)
Your code can be equivalently written:
#
print()
print(‘Some things I learned so far:’)
print()
#
print by default goes to the next line. try
print(" ",end = "")
so you can see '\t' more clearly.
Also, tab jumps to the next block. A block is usually 4 spaces.
Try this and notice where the . is:
print("\t", end=".\n")
print("A\t", end=".\n")
print("ABC\t", end=".\n")
print("ABCD\t", end=".\n")
The statement print('\t') is printing a tab, then returning to the next line, as the default print function automatically adds a newline. So you can't see the tab, but it is there. When you add \n to the end of the string you print, it adds a line return in addition to the default line return.
To remove the default line return, specify the 'end' parameter of the print function:
print('abcd\n', end='')
This will only include one line return.
By default print put a new line at the end, to modify this behavior you can set the end parameter with end=""
Example:
print("this will use 2 lines \n")
print("this will use 1 line")
print("this will use 1 line \n", end="")
Since print() does give an '\n' string at the end of each output the command print('\n') gives the commandline string '\t\n'.
For more details please see the following well documented post Link
"\n" character is a newline character and when you print "\n" it sets the cursor to a new line. print always sets a new line in the end by default. But you can change that behavior by setting the value of end argument to an empty string.
print("hello", end="")
"\t" is a tab character
for i in range(20):
print("current number is\t", I)
# current number is 0
# current number is 1
# current number is 2
# current number is 3
# current number is 4
# current number is 5
# current number is 6
# current number is 7
# current number is 8
# current number is 9
# current number is 10
# current number is 11
# current number is 12
# current number is 13
# current number is 14
# current number is 15
# current number is 16
# current number is 17
# current number is 18
# current number is 19
Find more magic characters which can be useful in your programs

What causes this return() to create a SyntaxError?

I need this program to create a sheet as a list of strings of ' ' chars and distribute text strings (from a list) into it. I have already coded return statements in python 3 but this one keeps giving
return(riplns)
^
SyntaxError: invalid syntax
It's the return(riplns) on line 39. I want the function to create a number of random numbers (randint) inside a range built around another randint, coming from the function ripimg() that calls this one.
I see clearly where the program declares the list I want this return() to give me. I know its type. I see where I feed variables (of the int type) to it, through .append(). I know from internet research that SyntaxErrors on python's return() functions usually come from mistype but it doesn't seem the case.
#loads the asciified image ("/home/userX/Documents/Programmazione/Python projects/imgascii/myascify/ascimg4")
#creates a sheet "foglio1", same number of lines as the asciified image, and distributes text on it on a randomised line
#create the sheet foglio1
def create():
ref = open("/home/userX/Documents/Programmazione/Python projects/imgascii/myascify/ascimg4")
charcount = ""
field = []
for line in ref:
for c in line:
if c != '\n':
charcount += ' '
if c == '\n':
charcount += '*' #<--- YOU GONNA NEED TO MAKE THIS A SPACE IN A FOLLOWING FUNCTION IN THE WRITER.PY PROGRAM
for i in range(50):#<------- VALUE ADJUSTMENT FROM WRITER.PY GOES HERE(default : 50):
charcount += ' '
charcount += '\n'
break
for line in ref:
field.append(charcount)
return(field)
#turn text in a list of lines and trasforms the lines in a list of strings
def poemln():
txt = open("/home/gcg/Documents/Programmazione/Python projects/imgascii/writer/poem")
arrays = []
for line in txt:
arrays.append(line)
txt.close()
return(arrays)
#rander is to be called in ripimg()
def rander(rando, fldepth):
riplns = []
for i in range(fldepth):
riplns.append(randint((rando)-1,(rando)+1)
return(riplns) #<---- THIS RETURN GIVES SyntaxError upon execution
#opens a rip on the side of the image.
def ripimg():
upmost = randint(160, 168)
positions = []
fldepth = 52 #<-----value is manually input as in DISTRIB function.
positions = rander(upmost,fldepth)
return(positions)
I omitted the rest of the program, I believe these functions are enough to get the idea, please tell me if I need to add more.
You have incomplete set of previous line's parenthesis .
In this line:-
riplns.append(randint((rando)-1,(rando)+1)
You have to add one more brace at the end. This was causing error because python was reading things continuously and thought return statement to be a part of previous uncompleted line.

Formatting output from print on respective lines?

I am trying to format the results of a query such that results are printed on their respective lines. For example, I am querying stores by store number and obtaining the location from a JSON file, but when printing, the store number and location are printing on separate lines:
Code Snippet: (Searching for stores 35 and 96)
for store, data in results.items():
print('Store: {}'.format(store))
if data:
for location in data:
print(location)
Current Output:
Store: 35
{'location': Iowa}
Store: 96
{'location': Minnesota}
Desired output (or something similar):
Store: 35, 'location': Iowa
Store: 96, 'location': Minnesota
Adding end='' to your first print statement should fix the problem. By specifying that the end character is an empty string you will override the default \n character (by default print statements end with a new line character).
for store, data in results.items():
print('Store: {}'.format(store), end='')
if data:
for location in data:
print(location)
We will only add end='' to the first print statement because we want the new line to print after you print out the location.
If you want to separate your prints with a , of course you would just add + ',' to your first print statement.
This will work right off the bat if you're using Python 3. If you're using Python 2.X you will have to add this line to the top of your file: from __future__ import print_function
Here's a simple example of this in action:
from __future__ import print_function
l1 = ['hello1', 'hello2', 'hello3']
l2 = ['world1', 'world2', 'world3']
for i,j in zip(l1, l2):
print (i, end='')
print (j)
Output:
hello1world1
hello2world2
hello3world3
If we took the same code but altered it slightly and just removed the end='', this is what would happen:
from __future__ import print_function
l1 = ['hello1', 'hello2', 'hello3']
l2 = ['world1', 'world2', 'world3']
for i,j in zip(l1, l2):
print (i)
print (j)
Output:
hello1
world1
hello2
world2
hello3
world3
As you can see each line would end with a new line character, this printing a new line for each statement.
I would write all the output in a variable and print the variable only once at the end. This also allows you to save time (despite using more memory) since you need only a single access to the stdout. The code is also easier to follow (in my opinion):
output = ''
for store, data in results.items():
output += 'Store: {}'.format(store)
if data:
for location in data:
output += location+'\n'
# Only at the end you print your output
print(output)
You can also print at the end of each iteration (you still access half of the times to the stdout) with the following:
for store, data in results.items():
output = 'Store: {}'.format(store)
if data:
for location in data:
output += location+'\n'
# Print only at the end of the loop
print(output)
If you want a new line for each Store but not for each "location":
output = ''
for store, data in results.items():
output += 'Store: {}'.format(store)
if data:
for location in data:
output += location
output += '\n'
# Only at the end you print your output
print(output)
I think this approach is much more flexible, easier to read in the code and is also faster.
Hope to be helpful

Returning every instance of whatever's between two strings in a file [Python 3]

What I'm trying to do is open a file, then find every instance of '[\x06I"' and '\x06;', then return whatever is between the two.
Since this is not a standard text file (it's map data from RPG maker) readline() will not work for my purposes, as the file is not at all formatted in such a way that the data I want is always neatly within one line by itself.
What I'm doing right now is loading the file into a list with read(), then simply deleting characters from the very beginning until I hit the string '[\x06I'. Then I scan ahead to find '\x06;', store what's between them as a string, append said string to a list, then resume at the character after the semicolon I found.
It works, and I ended up with pretty much exactly what I wanted, but I feel like that's the worst possible way to go about it. Is there a more efficient way?
My relevant code:
while eofget == 0:
savor = 0
while savor == 0 or eofget == 0:
if line[0:4] == '[\x06I"':
x = 4
spork = 0
while spork == 0:
x += 1
if line[x] == '\x06':
if line[x+1] == ';':
spork = x
savor = line[5:spork] + "\n"
line = line[x+1:]
linefinal[lineinc] = savor
lineinc += 1
elif line[x:x+7] == '#widthi':
print("eof reached")
spork = 1
eofget = 1
savor = 0
elif line[x:x+7] == '#widthi':
print("finished map " + mapname)
eofget = 1
savor = 0
break
else:
line = line[1:]
You can just ignore the variable names. I just name things the first thing that comes to mind when I'm doing one-offs like this. And yes, I am aware a few things in there don't make any sense, but I'm saving cleanup for when I finalize the code.
When eofget gets flipped on this subroutine terminates and the next map is loaded. Then it repeats. The '#widthi' check is basically there to save time, since it's present in every map and indicates the beginning of the map data, AKA data I don't care about.
I feel this is a natural case to use regular expressions. Using the findall method:
>>> s = 'testing[\x06I"text in between 1\x06;filler text[\x06I"text in between 2\x06;more filler[\x06I"text in between \n with some line breaks \n included in the text\x06;ending'
>>> import re
>>> p = re.compile('\[\x06I"(.+?)\x06;', re.DOTALL)
>>> print(p.findall(s))
['text in between 1', 'text in between 2', 'text in between \n with some line breaks \n included in the text']
The regex string '\[\x06I"(.+?)\x06;'can be interpreted as follows:
Match as little as possible (denoted by ?) of an undetermined number of unspecified characters (denoted by .+) surrounded by '[\x06I"' and '\x06;', and only return the enclosed text (denoted by the parentheses around .+?)
Adding re.DOTALL in the compile makes the .? match line breaks as well, allowing multi-line text to be captured.
I would use split():
fulltext = 'adsfasgaseg[\x06I"thisiswhatyouneed\x06;sdfaesgaegegaadsf[\x06I"this is the second what you need \x06;asdfeagaeef'
parts = fulltext.split('[\x06I"') # split by first label
results = []
for part in parts:
if '\x06;' in part: # if second label exists in part
results.append(part.split('\x06;')[0]) # get the part until the second label
print results

Python-Json Parser

I am trying to implement python Json parser with the following set of rules:
Rule 1:
A JSON data object always begins with curly braces and ends with curly braces.
{}
Rule 2:
All data is represented in the form of
"string":value
where the value can be any of the following:
number
string
boolean
another json
Rule 3:
The rules for forming the strings (on the left hand side in red) are similar to rules for variables in most programming languages.
* They can be alphanumeric, but should always begin with a letter.
* They are case sensitive
* They can not contain special characters except underscores.
I worked on it and completed all the conditions except "another json". Hee is my code
import re
import string
class parser(object):
fp=open('jsondata.txt','r')
str=fp.read()
def __init__(self):
print "Name of the file Opened is :",self.fp.name
print "Contents of the file :\n",self.str
def rule1(self,str):
if self.str[:1].startswith('{'):
if self.str[:-1].endswith('}'):
print "RULE 1\n",
print "first character is '{' last character is '} : passed rule1\n"
else:
print "Not a JSON data"
def splitdata(self):
self.str=self.str[1:]
self.str=self.str[:-2]
print self.str
#Storing the words of string in a list
self.list1=[]
self.list1=re.split(',',self.str)
self.list2=[]
self.list3=[]
for i in self.list1:
self.list2=list(re.split(':',i))
self.list3.extend(list(self.list2))
self.left_list=[]
self.right_list=[]
self.i=0
self.left_list=list([self.list3[i] for i in range(len(self.list3)) if i % 2 == 0])
self.right_list=list([self.list3[i] for i in range(len(self.list3)) if i % 2 == 1])
print "DATA SPLIT"
print "Left elements of the json data:",self.left_list
print "Right elements of the json data:",self.right_list,"\n"
def left_parse(self):
"""we gona check "This part of the string":"This part will be checked in next function"\
Conditions imposed on left part of string:\
1.starts and ends with ""\
2.Starts with Alphabet\
3.Contains No special characters except unserscore _"""
for i in range(len(self.left_list)):
self.str1=self.left_list[i]
if self.str1.startswith('"') and self.str1.endswith('"')\
and self.str1[1].isalpha():
self.str2=self.str1[1:]
self.str3=self.str2[:-1]
print "Left side content:",self.str3
print "Status : Valid"if re.match("^[a-zA-Z0-9_]*$", self.str3) else "Invalid"
else:
print "Left side content:",self.str1
print "Status: Invalid"
obj=parser()
obj.rule1(str)
obj.splitdata()
obj.left_parse()
Now the problem is When i tried to check my right_list, whenever i get Another json data then the output goes wild. Can anyone please help me. i framed left_list and right_list based on splitting(comma and colon).
While parsing json inside a json this logic seems not working...

Categories