Вводящая в заблуждение глобальная переменная

У меня есть упражнение, и теперь оно хорошо и работает. Алгоритм этого упражнения - загрузить файлы с FTP-сервера, сжать их и снова загрузить в папку загрузки на FTP-сервере. Кстати это мой код:

import os
import zipfile
import ConfigParser
import ftputil
import shutil
import tempfile
import time


def download_files():
    # Alvin: Think of a better variable name
    file_list = ftp.listdir(downloads)
    for filename in file_list:
        # Alvin should be ftp.path.join
        source = os.path.join(downloads, filename)
        target = os.path.join(temp_path, filename)
        ftp.download(source, target)

def zipping_files():
    dirlist = os.listdir(temp_path)
    global filepath
    filepath = os.path.join(temp_path, 'part2b.zip')
    # Alvin: find better name for zip_name
    global zip_name
    zip_name = zipfile.ZipFile(filepath, 'w')
    # Alvin: try not to use built-in names as variable names
    for list in dirlist:
        # Alvin: file_path, absolute_path
        get_file = os.path.join(temp_path, list)
        zip_name.write(get_file, 'part2b\\' + list)

def upload_files():
    ftp.upload(filepath, uploads + '/part2b.zip')

def main():
    # Alvin: Do not use globals.
    # Alvin: remove useless and above all misleading comments

    global temp_path
    temp_path = tempfile.mkdtemp()


    config = ConfigParser.ConfigParser()
    config.readfp(open('config.ini'))
    server = config.get('main', 'Server')
    username = config.get('main', 'Username')
    password = config.get('main', 'Password')

    global uploads
    uploads = config.get('main', 'Upload folder')

    global downloads
    downloads = config.get('main', 'Download folder')

    #connect to ftp
    global ftp
    # Alvin: open ftp connection when you only need it.
    ftp = ftputil.FTPHost(server, username, password)

    try:
        download_files()
        zipping_files()
        upload_files()

    finally:
        ftp.close()
        zip_name.close()
        shutil.rmtree(temp_path, 'true')

    print "Successfully transferred files."
    print ""
    print "This will close in 5 seconds. . . . ."
    time.sleep(5)

if __name__ == '__main__':
    main()

Хорошо, соглашения об именах оставляют это для меня. Но я хочу попросить привести пример того, как я могу перекодировать его, не используя все мои глобальные переменные? Спасибо за вашу помощь!

4 ответа

Решение

Вы должны точно указать параметры для ваших методов.

Вот как вы можете продолжить:

  1. Определите, что делает ваш метод, каждый должен иметь только одну точную цель
  2. Определите, что для этого нужно, и внесите в список аргументов.
  3. Определите, что он должен вернуть и вернуть его
  4. Ваша основная функция в порядке, и это идеальное место для централизации этих переменных

Один из самых лучших моментов неиспользования глобальных переменных и наличия одного метода / одного метода - это то, что будет очень легко тестировать / отлаживать, когда что-то пойдет не так.

Пример:

ваш download_files() требует downloads а также temp_pathаргументы, а не глобальные

У вас есть четыре глобала в вашем main по состоянию на сейчас. (temp_path, uploads, downloads а также ftp).

Сначала удалите (закомментируйте) строки с глобальным, а затем эти 4 переменные станут локальными для main, Но это сделало бы их недоступными для других функций. Итак, вам нужно передать их в функции.

Для этого вы можете добавить эти переменные в качестве параметров к функциям, которые их требуют. Так, например, вы try блок изменится на..

try:
    download_files(downloads, temp_path)
    zipping_files(temp_path)
    upload_files(ftp)

Теперь, чтобы соответствовать добавлению параметров, вы также должны изменить функции. Подписи функций, которые вызываются из try блок будет:

def download_files(downloads, temp_path):

def zipping_files(temp_path):

def upload_files(ftp):

Точно так же вы можете удалить глобальные переменные, которые есть в других функциях (например, global filepath в zipping_files()).

Спасибо, ребята, за вашу помощь! Все ваши ответы очень полезны! Это мой последний и работающий код:

import os
import zipfile
import ConfigParser
import ftputil
import shutil
import tempfile
import time


def download_files(downloads, temp_path, server, username, password):
    ftp = ftputil.FTPHost(server, username, password)
    file_list = ftp.listdir(downloads)
    for filename in file_list:
        source = os.path.join(downloads, filename)
        target = os.path.join(temp_path, filename)
        ftp.download(source, target)
    ftp.close()

def zipping_files(temp_path):
    file_list = os.listdir(temp_path)
    filepath = os.path.join(temp_path, 'part2b.zip')
    zip_file = zipfile.ZipFile(filepath, 'w')
    for filename in file_list:
        file_path = os.path.join(temp_path, filename)
        zip_file.write(file_path, 'part2b\\' + filename)
    zip_file.close()

def upload_files(uploads, temp_path, server, username, password):
    ftp = ftputil.FTPHost(server, username, password)
    filepath = os.path.join(temp_path, 'part2b.zip')
    ftp.upload(filepath, uploads + '/part2b.zip')
    ftp.close()

def main():

    temp_path = tempfile.mkdtemp()

    config = ConfigParser.ConfigParser()
    config.readfp(open('config.ini'))
    server = config.get('main', 'Server')
    username = config.get('main', 'Username')
    password = config.get('main', 'Password')
    uploads = config.get('main', 'Upload folder')
    downloads = config.get('main', 'Download folder')

    try:
        download_files(downloads, temp_path, server, username, password)
        zipping_files(temp_path)
        upload_files(uploads, temp_path, server, username, password)

    finally:    
        shutil.rmtree(temp_path, 'true')

    print "Successfully transferred files."
    print ""
    print "This will close in 5 seconds. . . . ."
    time.sleep(5)

if __name__ == '__main__':
    main()

Любые предложения все будут рассмотрены! Еще раз спасибо!

Python на самом деле не поддерживает глобальные переменные - они вообще плохая идея. Либо передайте данные в качестве аргументов, либо заключите ваши функции в класс и используйте параметры в качестве членов класса.

(Технически, у python есть глобальное ключевое слово, но вы должны использовать его в каждой функции для каждой глобальной переменной. Это ужасно, как и должно быть. Не используйте его.)

Другие вопросы по тегам