Use of global variables in script - python-2.7

I threw the 'Apple-code' in the trash, please look at the following code :
# Define processing inputted line
def inputfile(line):
linecontents = { 'item_0110': line[0:8],
'item_0111': line[8:16],
'item_0112': line[16:24] }
print 'In the function : ', linecontents
print 'In the function : ', len(linecontents)
# Set dictionary
linecontents = {}
# Pretend to open a file and read line for line
line = '010012343710203053525150'
# Start processing the read line
inputfile(line)
# Display end resultprint
print '\nOutside the function : ', linecontents
print 'Outside the function : ', len(linecontents)
Ok, first off : I'm an idiot for trying this with vars. In the original post I already stated I have more than thirty items (fields if you want) in the file. To make matters more complex, a line from the file could look like this :
010012343710203053525150
And not all lines have the same fields so depending on what type of field it is, I would like to call a different function.
The question now is : why is the output like this :
In the function : {'item_0112': '53525150', 'item_0111': '37102030', 'item_0110': '01001234'}
In the function : 3
Outside the function : {}
Outside the function : 0
I thought the dictionary is independent from functions and/or classes ?

There are some issues with your code. I don't really see the see for global variables here.
I reformatted and refactored your code (no uppercase except for classes). You intent is not clear so I tried my best. The function read_file actually reads you file line by line and returns customer_name and customer_item line by line.
def read_file(filepath):
with open(filepath) as customer_file:
for line in customer_file:
customer_name = line[:10]
customer_item = line[10:]
print('Name : ' + customer_name)
print('Item : ' + customer_item)
yield customer_name, customer_item
In the main() or whatever function, you can do what you want with the customer's variables.
What is important here, is that read_file actually reads a file and process the information for the file before returning them to the calling function.
def main():
myfile = 'CustomerFile.txt'
for customer_name, customer_item in read_file(myfile):
if customer_item == 'Apple':
print(customer_name)
else:
print(customer_name + ' is not eating an apple')

Instead of using globals, let the ReadFile function return the values
def ReadFile(line):
...
return CustomerName, CustomerItem
and assign them to variables after calling the function:
for line in CustomerFile:
CustomerName, CustomerItem = ReadFile(line)
def ReadFile(line):
CustomerName = line[0:10]
CustomerItem = line[10:]
return CustomerName, CustomerItem
def Report(CustomerName, CustomerItem):
# Try to keep all print statements in one place
print 'Name : ' + CustomerName
print 'Item : ' + CustomerItem
if CustomerItem == 'Apple':
print CustomerName
else:
print CustomerName + ' is not eating an apple'
with open(CustomerFile.txt) as CustomerFile:
for line in CustomerFile:
CustomerName, CustomerItem = ReadFile(line)
Report(CustomerName, CustomerItem)
Note that the PEP8 style guide recommends using lower_case for variable and function names and to reserve CamelCase for classes. While you are free to use your own style, use of PEP8 is quite prevalent and so by joining the PEP8-club your code will more naturally "fit in" with other people's code and vice-versa.

I found the (obvious) answer. As I said, my Python is a bit rusty :
## Define processing inputed line
#
def inputfile(line, linecontents):
linecontents['item_0110'] = line[0:8]
linecontents['item_0111'] = line[8:16]
linecontents['item_0112'] = line[16:24]
print 'In the function : ', linecontents
print 'In the function : ', len(linecontents)
## Define main script
#
def main():
# Set dict
linecontents = {}
# Pretend to open a file and read line for line
line = '010012343710203053525150'
# Start processing the read file
inputfile(line, linecontents)
# Display end resultprint
print '\nOutside the funtion : ', linecontents
print 'Outsude the function : ', len(linecontents)
## Start main script
#
main()
And this neatly returns :
In the function : {'item_0112': '53525150', 'item_0111': '37102030', 'item_0110': '01001234'}
In the function : 3
Outside the funtion : {'item_0112': '53525150', 'item_0111': '37102030', 'item_0110': '01001234'}
Outsude the function : 3

Related

PyCharm shows "PEP8: expected 2 blank lines, found 1"

Consider the following code:
def add_function(a, b):
c = str(a) + b
print "c is %s" % c
def add_int_function(c, d):
e = c + d
print "the vaule of e is %d" % e
if __name__ =="__main__":
add_function(59906, 'kugrt5')
add_int_function(1, 2)
It always shows me: "expected 2 blank lines ,found 1" in aadd_int_function, but not in the add_function.
When I add two spaces in front of the def add_int_function(c, d):
there is a error shows unindent does not match any outer indentation level
in the end of add_function:
Just add another line between your function definitions :
1 line :
2 lines:
This is a pretty common question within the python community. After the release of PEP 8, new formatting styles were accepted into python. One of them states that after the definition of a class or function there must be two lines separating them. As such:
def yadayada:
print("two lines between the functions")
def secondyadayada:
print("this is the proper formatting")
So, you should never do it like:
def yadayada:
print("two lines between the functions")
def secondyadayada:
print("this is the proper formatting")
Or else PyCharm will throw that error at you.
Further clarification on #kennet-celeste & #shreyshrey 's answers,
Each function or class defined requires 2 spaces above and 2 spaces below. Unless the function is the last item in the script, in which the expected format is one blank line as an End of File marker. So:
# some code followed by 2 blank spaces
def function1():
def function2():
def function3():
For people who wonders why it requires two blank lines
if you were to write in other languages it would be:
fun doSth() {
print()
}
fun doSth1() {
print()
}
but if you were to delete all the curly braces from the code you will see:
two blank lines between methods
fun doSth()
print()
#
#
fun doSth1()
print()
#

how to exit from multiple loops in python

In my code below, I keep getting an error that I cant tell how to fix it.
See code:
def WordSelector():
global pattern
words = [location]
corpus = " ".join(words)
sentences1 = re.split(r'\.', corpus)
name17 = [name66, name666, name67, name68, name69, name612]
k1 = iter(name17)
keyword = next(k1)
pattern1 = keyword
class LocalBreak(Exception):
pass
try:
for pattern1 in name17:
for sentence in sentences1:
if pattern1 in sentence:
print 'code'
raise LocalBreak()
except LocalBreak:
pass
WordSelector()
I keep getting this error:
"C:\Python27\synonyms3.py", line 72, in LocalBreak
except LocalBreak:
NameError: free variable 'LocalBreak' referenced before assignment in enclosing scope
Whole try/except block is defined inside LocalBreak body, where you cannot reference class itself (since it's definition is not yet done).
Simply indent your code correctly and do your looping in fuction body, not in custom Exception definition scope.
def WordSelector():
global pattern
words = [location]
corpus = " ".join(words)
sentences1 = re.split(r'\.', corpus)
name17 = [name66, name666, name67, name68, name69, name612]
k1 = iter(name17)
keyword = next(k1)
pattern1 = keyword
class LocalBreak(Exception):
pass
try:
for pattern1 in name17:
for sentence in sentences1:
if pattern1 in sentence:
print 'code'
raise LocalBreak()
except LocalBreak:
pass
WordSelector()

python 2.7 - trying to print a string and the (printed) output of function in the same line

I have the following function defined:
def displayHand(hand):
"""
Displays the letters currently in the hand.
For example:
>>> displayHand({'a':1, 'x':2, 'l':3, 'e':1})
Should print out something like:
a x x l l l e
The order of the letters is unimportant.
hand: dictionary (string -> int)
"""
for letter in hand.keys():
for j in range(hand[letter]):
print letter, # print all on the same line
print '' # print an empty line
Now, I want to print the following:
Current hand: a b c
To do this, I try to do:
print "Current hand: ", displayHand({'a':1, 'b':1, 'c':1})
And I get:
Current hand: a b c
None
I know that None is printed cause I am calling the print function on the displayHand(hand) function, which doesn't return anything.
Is there any way to get rid of that "None" without modifying displayHand(hand)?
if you want to use your function in a print statement, it should return a string and not print something itself (and return None) - as you would do in a __str__ method of a class. something like:
def displayHand(hand):
ret = ''
for letter in hand.keys():
for j in range(hand[letter]):
ret += '{} '.format(letter) # print all on the same line
# ret += '\n'
return ret
or even
def displayHand(hand):
return ''.join(n*'{} '.format(k) for k,n in hand.items() )
When you trail a print with a ,, the next print will appear on the same line, so you should just call the two things on separate lines, as in:
def printStuff():
print "Current hand: ",
displayHand({'a':1, 'b':1, 'c':1})
Of course you could just adapt this and create a method like:
def printCurrentHand(hand):
print "Current hand: ",
displayHand(hand)
The only way to do this (or I believe the only way to do this) is to use return instead of print in your displayhand() function. Sorry if I didn't answer your question.
Your function 'displayHand' does not have to print the output,
it has to return a string.
def displayHand(hand):
mystring=''
for letter in hand.keys():
for j in range(hand[letter]):
mystring+= letter # concatenate all on the same line
return mystring
BUT, you have to check the '.keys' command help as the order of the input (a/b/c) may not be respected

Parse a file in various parts

I am trying to parse a file that contains the following
# This is 1st line
# This is 2nd line
ATOM This is 3rd line
ATOM This is 4th line
# This is 5th line
# This is 6th line
I wish to use Python 2.7 to parse the file and append lines up to the line starting with ATOM to a list head_list, the lines starting with ATOM to atom_list and lines after the line containing ATOM to a tail_list.
I want to use the startswith() in Python to match lines that start with ATOM. Below is my code, i am passing counter variable which has the index of the last line in the file which starts with ATOM. yet my output does not seem to be right
#!/usr/bin/python
import sys, os
global counter
def AskForFileName () :
file_name = raw_input('Enter the name of the input file \n')
try:
if not file_name :
print "You did not enter a name !"
except :
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno)
return file_name
def ReadFileContents (file_name) :
#print file_name
file = open(file_name,'r')
file_strings=file.readlines()
return file_strings
def BuildHeadList(all_file_contents) :
head_list=[]
i=0
try :
for line in all_file_contents:
if line.startswith("ATOM") :
break
else :
i=int(i)+1
#print "BuildHeadList :"+str(i)+"\n"
head_list.append(line)
except :
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno)
return head_list
def BuildAtomList(all_file_contents) :
atom_list=[]
i=0
global counter
try :
for i,line in enumerate(all_file_contents):
if line.startswith("ATOM") :
atom_list.append(line)
counter=i
#i=int(i)+1
#print "BuildAtomList :"+str(i)+"\n"
else :
continue
except :
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno)
return atom_list
def BuildTailList(all_file_contents) :
tail_list=[]
i=0
global counter
counter=counter+1
print "Counter value is "+str(counter)
try :
for i,line in enumerate(all_file_contents,counter):
print i
tail_list.append(line)
except :
exc_type, exc_obj, exc_tb = sys.exc_info()
fname = os.path.split(exc_tb.tb_frame.f_code.co_filename)[1]
print(exc_type, fname, exc_tb.tb_lineno)
return tail_list
def WriteNewFile(head_list,atom_list,tail_list):
file=open('output.txt', 'w')
#for line in head_list :
# print>>file, line,
#for line in atom_list :
# print>>file, line,
for line in tail_list :
print>>file, line,
file.close()
file_name=AskForFileName()
all_file_contents=ReadFileContents(file_name)
head_list=BuildHeadList(all_file_contents)
atom_list=BuildAtomList(all_file_contents)
tail_list=BuildTailList(all_file_contents )
WriteNewFile(head_list,atom_list,tail_list)
This line:
enumerate(all_file_contents, counter)
Doesn't do what you think it does; it iterates over everything in the lists, but numbers them starting from counter instead of 0. A minimal fix would be:
for i, line in enumerate(all_file_contents):
if i >= counter:
tail_list.append(line)
However, much better would be to not iterate over the whole file three times. In particular, note that tail_list = all_file_contents[counter:] gets the result you want. Additionally, get rid of the global and pass counter around explicitly.
You should also read the style guide.

How to fix a program that only works once?

def check_answer(self, currentscore):
self.user_entry = self.user_entry.get_text()
if self.user_entry == self.books:
self.current += 1
self.total += 1
self.currentscore = self.current
print "right"
else:
print "wrong"
print self.currentscore
print self.total
When i run it and i put text a second time is says File "C:\Python27\guessing.py", line 16, in check_answer
self.user_entry = self.user_entry.get_text()
AttributeError: 'str' object has no attribute 'get_text'
Could someone explain it to me. Why it to me why it only works once. and also why doesn't the program execute the if statement. It only says wrong.
self.books = 'hello'
You overwrite the variable holding the reference to the text box with its contents. So when check_answer runs for the first time, self.user_entry is your text box, and you can call its method get_text() to retrieve the text entered by the user. Unfortunately, you assign this text to the same variable (self.user_entry =) - so you loose the reference to the text box. After the first call, self.user_entry is a string (instance of str class) retrieved at the first call.
Use a different variable name, like this:
def check_answer(self, currentscore):
self.user_entry_text = self.user_entry.get_text()
if self.user_entry_text == self.books:
self.current += 1
self.total += 1
self.currentscore = self.current
print "right"
else:
print "wrong"
print self.currentscore
print self.total
Also, possibly it doesn't have to be class's field, so you can also skip the self. part. In such case you could use the same name (user_entry), but for sake of readability it's better to call a variable with a name that says precisely what the variable holds:
user_entry_text = self.user_entry.get_text()
if user_entry_text == self.books: