Python Tkinter get result of askopenfilenames() - python

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.

Related

Python Passing Variables Between Two Functions

I'm trying to have the first function to open the file and the second function to print the contents of the file. Running into a few errors if someone could help me out the would be great!
global strings
def open_file():
file = askopenfile(parent=root,mode ='r', filetypes =[("All files", "*")])
if file is not None:
content = file.read()
strings = content.splitlines()
return strings
def run_file(some_content):
for i in some_content:
print(bytes(i,"ascii"))
time.sleep(1)
btn_upload = Button(root, text="UPLOAD",bg='#34495e', fg='white', command = lambda:open_file())
btn_upload.pack()
btn_run = Button(root, text="RUN",bg='#34495e', fg='white', command=lambda:run_file(strings))
btn_run.pack()
You'll need to put global strings inside the open_file() function (and indeed in any function that assigns to that name; reading from globals works without global).
strings = None
def open_file():
global strings
# ...
def run_file():
for i in strings:
# ...
However, in the name of testability etc., I'd avoid using global variables and maybe just encapsulate your state into a class.

How do I pass a variable between functions python

Here are my two functions:
def selectBadge(a):
curItem = SelectBadgeView.focus()
inter_var = SelectBadgeView.item(curItem)
ListValues = inter_var['values']
print(ListValues)
SelectedBadge.set("Selected Badge: "+str(ListValues[0]))
SelectedBadgeStr=str(ListValues[0])
return SelectedBadgeStr
def selectScout(a,SelectedBadgeStr):
print(a)
if SelectedPatrol.get()==("Selected Patrol: Please Select A Patrol"):
tk.messagebox.showerror("ERROR","Please select a Patrol")
return
if SelectedBadge.get()==("Selected Badge: Please Select A Badge"):
tk.messagebox.showerror("ERROR", "Please select a Badge")
return
print(SelectedBadgeStr)
return
I want to pass the variable SelectedBadgeStr from selectBadge() to selectScout().
The variable a is a internal variable used by the tkinter treeview widget.
a = <ButtonRelease event state=Button1 num=1 x=144 y=39>
I have tried:
return SelectedBadgeStr
However this did not work.
The function is called by:
SelectScoutView.bind('<ButtonRelease-1>', selectScout)
Did you declare SelectedBadgeStr as for example an empty string before defining the function selectBadge(a)?
So just declare it like:
SelectedBadgeStr = ''
def selectBadge(a):
curItem = SelectBadgeView.focus()
.
.
.
It should work.
You can also use a shared global variable:
Declare the variable outside of the functions use:
SelectedBadgeStr = None
At the beginning of the functions use:
global SelectedBadgeStr
Whenever you use the variable now within the functions, you access the global variable

Python global variable empty in function

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).

Variable referenced before assignment - Python

I am getting the error...
a = a + b
UnboundLocalError: local variable 'a' referenced before assignment
I don't understand why the error occurs if I have assigned the two variables a and b at the start.
from tkinter import *
a = 10
b = 12
def stopProg(e):
root.destroy()
def addNumbers(e):
a = a + b
label1.configure(text= str(a))
root=Tk()
button1=Button(root,text="Exit")
button1.pack()
button1.bind('<Button-1>',stopProg)
button2=Button(root,text="Add numbers")
button2.pack()
button2.bind('<Button-1>',addNumbers)
label1=Label(root,text="Amount")
label1.pack()
root.mainloop()
Whenever you modify a global variable inside a function, you need to first declare that variable as being global.
So, you need to do this for the global variable a since you modify it inside addNumbers:
def addNumbers(e):
global a
# This is the same as: a = a + b
a += b
# You don't need str here
label1.configure(text=a)
Here is a reference on the global keyword.
Also, I would like to point out that your code can be improved if you use the command option of Button:
from tkinter import *
a = 10
b = 12
def stopProg():
root.destroy()
def addNumbers():
global a
a += b
label1.configure(text=a)
root=Tk()
button1=Button(root, text="Exit", command=stopProg)
button1.pack()
button2=Button(root, text="Add numbers", command=addNumbers)
button2.pack()
label1=Label(root, text="Amount")
label1.pack()
root.mainloop()
There is never a good reason to use binding in place of the command option.
Here is your answer :
This is because when you make an assignment to a variable in a scope, that variable becomes local to that scope and shadows any similarly named variable in the outer scope.
Please read this : http://docs.python.org/2/faq/programming.html#why-am-i-getting-an-unboundlocalerror-when-the-variable-has-a-value
You are modifying a global variable. By default, you can read values from global variables, without declaring them as global, but to modify them you need to declare them as global like this
global a
a = a + b

Increment variable in callback during upload

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()

Categories