So I've got a couple global variables: directory_name and file_list
They're defined at the top and then I give them values in main. I need their values in a function called checkDirectory(blocknum). If I print their values before I call the function, they're correct, but in the function they are empty. This is some of the code:
file_list = []
directory_name = ""
def checkDirectory(blocknum):
global directory_name
global file_list
directory = tokenize(open(directory_name + '/' + file_list[blocknum], 'r').read())
main():
try:
directory_name = sys.argv[1]
if not os.path.exists(directory_name):
print("This is not a working directory.")
return
except:
directory_name = os.getcwd()
files = os.listdir(directory_name)
file_list = sorted(files, key=lambda x: int((x.split("."))[1].strip()))
....
checkDirectory(26)
This is a basic 100 line script, and I can pass in the variables but I'll have to do that for three or four functions which will be recursive, so I'd rather not have to do it every time.
You are shadowing directory_name and file_list in your main function. Since those variables are not known in that scope, they get created locally. In order to operate on the global variables, you need to declare them global in your main() as well:
file_list = []
directory_name = ""
def checkDirectory(blocknum):
global directory_name
global file_list
directory = tokenize(open(directory_name + '/' + file_list[blocknum], 'r').read())
main():
global directory_name
global file_list
...
Please remember that, as mentioned in the comments, using globals is not good practice and can lead to bad code in the long run (in terms of unreadable/unmaintainable/buggy).
Related
I use Tkinter as GUI library and i need to get list of files which i choose by calling askopenfilenames.
Here is my function^
def choose_file(file_list)
file_list = fd.askopenfilenames()
file_list = ()
b1 = Button(command = lambda: choose_file(file_list))
file_list - is variable in outer scope. But after calling function, this var is empty. What i did wrong?
Try:
import tkinter.filedialog as fd
import tkinter as tk
def choose_file():
global file_list
file_list = fd.askopenfilenames()
file_list = ()
root = tk.Tk()
b1 = tk.Button(root, text="Click me", command=choose_file)
b1.pack()
root.mainloop()
The variable file_list is not global as it is immutable. To make it global you have to add global file_list to the start of your function definition. For more info read: Why you can change immutable if it's global.
You have two different file_list variables in your code. One at global scope
file_list = ()
and one at function scope.
def choose_file(file_list):
With
file_list = fd.askopenfilenames()
you are assigning the list returned by askopenfilenames to the function scope variable - everywhere in the function, file_list will have the list from askopenfilenames as value, what you can see by adding print(file_list) to your function twice, one time at the beginning and one time at the end.
To modify the global variable instead of the local one, you can either make the local (function scope) variable global
file_list = ()
def choose_file():
global file_list
file_list = fd.askopenfilenames()
b1 = Button(command = choose_file)
where the variable initialization must be moved before the function declaration (I think else it gives an UnboundLocalError or something), the lambda can be removed, and you do not need to pass file_list as an argument.
I am trying to create a simple search engine to look inside a file. In order to reuse the code I separated the search function, but for some reason it just doesn't work the second time round.
The first time round it shows the result as it should but the second time I type a name it doesn't give me any result at all. Its like the c variable is not going in to the searchpart(c, path) function the second time round.
import os
def searchpart(c, path):
employees = os.walk(path)
for root, dirs, files in employees:
names = os.path.basename(root)
if c.lower() in names.lower():
print(root)
os.chdir(root)
for i in os.listdir():
print("-----> {}".format(i))
def welcomepart(path):
# this function allows to reuse the application after a name is search.
c = input("\n-------> please introduce the name? \n")
searchpart(c, path)
def mainfuntion():
path = 'WORKERS'
invalid_input = True
print('______________ Welcome ______________ \n ')
while invalid_input:
welcomepart(path)
mainfuntion()
This work-around seems to fix the problem:
def searchpart(c, path):
cwd = os.getcwd()
employees = os.walk(path)
for root, dirs, files in employees:
names = os.path.basename(root)
if c.lower() in names.lower():
print(root)
os.chdir(root)
for i in os.listdir():
print("-----> {}".format(i))
os.chdir(cwd)
It just remembers which directory you were in before the function call and changes back before returning.
However, I'm sure there will be a solution where the line: os.chdir(root) is not needed.
I've made a button that creates a txt file and I wanted to make it so that their names are "test1.txt", "test2.txt", "test3.txt", ... and the number would change everytime you create a new file, but it keeps setting it back to 1.
here's my code:
def createtxt(txtfile_number):
filename = "test" + str(txtfile_number) + ".txt"
open(filename, "w")
txtfile_number += 1
print(txtfile_number)
def createtxt_Launch():
createtxt(txtfile_number)
[...]
txtfile_number = 1
createTxtFile_button = Button(menu, text="Create txt file", width=15, command=createtxt_Launch)
I know theproblem is because of the line "txtfile_number = 1" but I don't know how to make it so that it only runs that command once
I'm assuming you're creating your button in the global scope (i.e. not inside a function or method or a module that's different from the one createtxt is in).
Make txtfile_number a global value, and increment it in createtxt_Launch instead of in createtxt.
def createtxt(number):
filename = "test" + str(number) + ".txt"
open(filename, "w")
print(number)
def createtxt_Launch():
global txtfile_number
createtxt(txtfile_number)
txtfile_number += 1
I have the following python script for an upload that needs to show percent done. I am having trouble incrementing the variable that tracks the amount of data transferred.
I get an
UnboundLocalError: local variable 'intProgress' referenced before assignment
error. Yet if I try to print this variable it prints fine so it seems that it is referenced.
import os, sys, ftplib
pathname = 'C:/Paradigm1/1.PNG'
intFileSize = os.path.getsize(pathname)
intPercentDone = 0
intProgress = 0
def callback(p):
intProgress = intProgress + 1024
##sys.stdout.write(str(intProgress))
sys.stdout.write("-")
session = ftplib.FTP('Server','UserName','Password')
f = open(pathname,'rb')# file to send
session.storbinary('STOR /Ftp Accounts/PublicDownloads/test.png', f, 1024, callback)
f.close()
If you want the callback() function to change the global variable intProgress, you have to declare it as global in the function...
def callback(p):
global intProgress
intProgress = intProgress + 1024
##sys.stdout.write(str(intProgress))
sys.stdout.write("-")
...otherwise it'll assume intProgress is a local variable, and get confused by the fact that you're trying to reference it when setting it.
intProgress = inside a function forces Python to treat it as a local variable overshadowing the variable from the outer scope.
To avoid mutable globals, you could create a closure:
import os
import sys
def make_callback(filesize):
total = [0] # use list to emulate nonlocal keyword
width = len(str(filesize))
def report_progress(block):
total[0] += len(block)
sys.stderr.write("\r{:{}d} / {}".format(total[0], width, filesize))
return report_progress
def main():
# ...
ftp.storbinary(..., make_callback(os.path.getsize(filename)))
main()
I wrote the below code in order to check for three files and whichever files exist, run a "scan" on the file (if a file does not exist, don't worry about it just run a "scan" on the available files) and produce the proper output file on those available files.
The program I'm working on includes the following code:
def InputScanAnswer():
scan_number = raw_input("Enter Scan Type number: ")
return scan_number
This function checks if these three files exist and if so, assign specific values to hashcolumn and to filepathNum
def chkifexists():
list = ['file1.csv', 'file2.csv', 'file3.csv']
for filename in list:
if os.path.isfile(filename):
if filename == "file1.csv":
hashcolumn = 7
filepathNum = 5
if filename == "file2.csv":
hashcolumn = 15
filepathNum = 5
if filename == "file3.csv":
hashcolumn = 1
filepathNum = 0
#print filename, hashcolumn, filepathNum
def ScanChoice(scan_number):
if scan_number == "1":
chkifexists()
onlinescan(filename, filename + "_Online_Scan_Results.csv", hashcolumn, filepathNum) #this is what is giving me errors...
elif scan_number == "2":
print "this is scan #2"
elif scan_number =="3":
print "this is scan #3"
else:
print "Oops! Invalid selection. Please try again."
def onlinescan(FileToScan, ResultsFile, hashcolumn, filepathNum):
# web scraping stuff is done in this function
The error that I run into is global name 'filename' is not defined.
I realize that the problem is I'm attempting to send local variables from chkifexists() to the onlinescan() parameters. I tried using
return filename
return hashcolumn
return filepathNum
at the end of the chkifexists() function but that was not working either. Is there anyway to do what I'm trying to do in the
onlinescan(filename, filename + "_Online_Scan_Results.csv", hashcolumn, filepathNum)
line without using global variables? I know they are discouraged and I'm hoping I can go about it another way. Also, does having hashcolumn and filepathNum parameters in onlinescan() have anything to do with this?
Inside chkifexists, you would return all three variables like so:
return (filename, hashcolumn, filepathNum)
You would retrieve these by calling the function like so:
(filename, hashcolumn, filepathNum) = chkifexists()
You now have them in your function scope without needing global variables!
Technically, you don't need the parenthesis, either. In fact, I'm not sure why I included them. But it works either way, so what the heck.