While writing a function that will show a progress bar while downloading a list of files from an ftp server I ended up with some strange script:
with ftplib.FTP(...) as ftp:
  files = list(ftp.mlsd(path=remote_dir_path))
  total_size = sum(int(f[1]['size']) for f in files)
  total_done = 0
  current_done = 0
  current_size = 0
  def callback(chunk):
    global current_done
    global total_done
    global current_size
    global total_size
    trg_file.write(chunk) # how? why it knows what is `trg_file`?
    current_done += len(chunk)
    total_done += len(chunk)
    print_progressbar(current_done,total_done,...)
  for file in files:
    current_done = 0
    current_size = int(file[1]['size'])
    with open(file[0],'wb') as trg_file:
      ftp.retrbinary('RETR %s/%s'%(remote_dir_path,file[0]),callback)
I had to write global in callback function so that python does not complain about it. BUT it knew what is trg_file no problem?!?!?!
Trying to understand I wrote a small test:
def callback():
  print(foo)
def main():
  foo = 'FOOOO'
  callback()
main()
It failed as expected.
I get why the second script does not work. Intuition says that the first should not work too. But it works. Can somebody please explain why?
EDIT:
The question is not about global itself, but about with ... as ... block and scope (scope of ... as variable variable)
 
    