У меня есть функция под названием USB(), что будет понаблюдайте за вставкой usb-флешки и удалите файлы внутри нее, если они есть:
import os
import shutil
# 1. Check and clean USB
def USB():
usb_inserted = os.path.isdir("F:") # <-- returns boolean...checks whether a directory exists
if usb_inserted == False:
print("nnUSB stick is not plugged in. Waiting for connection...")
while usb_inserted == False: # wait
""" updating variable, because it takes only the return value of function 'isdir()'
and stays the same regardless of the fact, that 'isdir()' changed """
usb_inserted = os.path.isdir("F:")
continue
SECURITY_FILE = "System Volume Information"
if os.listdir("F:") == [SECURITY_FILE] or os.listdir("F:") == []: # if list of files contains only the security file (is empty)
print("nUSB flash is already empty.") # send a message and continue
else:
files = os.listdir("F:") # list of names of files in the usb flash, that will be deleted
if SECURITY_FILE in files:
""" taking out the security file from the list, because attempting to delete it causes
'PermissionError [WinError 5]' exception """
files.remove(SECURITY_FILE)
for file in files: # Loop through the file list
if os.path.isfile(f"F:\{file}"): # if it's a file
os.remove(f"F:\{file}") # Delete the file
elif os.path.isdir(f"F:\{file}"): # if it's a directory/folder
shutil.rmtree(f"F:\{file}") # remove the folder
print("nAll files/folders are deleted from USB.")
USB()
Есть ли что-нибудь, что можно улучшить с точки зрения более чистого кода или вещей, которые я мог пропустить во время тестирования?
3 ответа
Логические проверки
Вместо того, чтобы делать:
if usb_inserted == False:
# do something
использовать
if not usb_inserted:
# do something
while not usb_inserted
Этот цикл while будет обрабатывать вызов файловой системы, чтобы проверить, существует ли диск. Вместо этого я бы проверял раз в несколько секунд:
from time import sleep
def wait_for_usb():
while True:
if os.path.isdir('F:'):
break
else:
# give user notification it's still waiting
print('Detecting...')
time.sleep(2)
Проверка содержимого списка
Чтобы проверить пустой список, вы можете полагаться на его истинность вместо явной проверки на равенство:
# instead of this:
if os.listdir("F:") == []:
# do something
# do this
if not os.listdir('F:'):
# do something
Более того, было бы лучше проделать эту операцию только один раз:
# This might be a better check for the security file
def only_contains_security_file(contents):
return len(contents) == 1 and contents[0] == "System Volume Information"
# only grab contents once
contents = os.listdir('F:')
if not contents or only_contains_security_file(contents):
print("nUSB flash is already empty.")
Итерация по файлам
Поскольку вы просто хотите прогуляться по дороге на высшем уровне, вы можете использовать os.scandir
вместо повторения os.listdir
. У этого есть несколько преимуществ. Во-первых, он не объединяет все в list
(недостаток в том, что os.walk
есть для этого использования) и что он автоматически позволяет вам проверять типы:
for item in os.scandir('F:'):
if item.name.endswith("System Volume Information"):
continue
elif item.is_file():
os.remove(item.path)
else:
shutil.rmtree(item.path)
Это также полезно, если ваш USB-порт заполнен множеством файлов с длинными именами.
Вам также не нужно проверять, пуст ли он, ваш цикл просто пропустит все, если это так.
Добавление if __name__ == "__main__"
сторожить
Это полезно для сценариев, которые вы, возможно, захотите запустить, но также хотите импортировать что-то из. С этим защитным устройством, если вы импортируете что-то из модуля usb из другого скрипта Python, он не выполнит ваш скрипт. Это приятно, учитывая, что у вас бесконечный цикл:
def usb():
# your code
if __name__ == "__main__":
usb()
Итак, в целом:
import os
import shutil
from time import sleep
def wait_for_usb():
print("Waiting for usb at F:")
while True:
if os.path.isdir('F:'):
break
else:
print("Detecting...")
time.sleep(2)
def usb():
wait_for_usb()
for item in os.scandir('F:'):
if item.name.endswith("System Volume Information"):
print('Skipping system info file')
continue
elif item.is_file():
print(f"Removing file {item.path}")
os.remove(item.path)
else:
print(f"Removing directory {item.path}")
shutil.rmtree(item.path)
print('USB is now empty')
if __name__ == "__main__":
usb()
Решение производственного уровня вообще не будет иметь цикла опроса и будет полагаться на ловушку уведомления об изменении файловой системы. Есть много, много способов делать это с разной степенью портативности и простоты использования; на вашем месте я бы использовал что-нибудь портативное и готовое, например сторожевая собака.
Рекомендуется следовать PEP8 для удобочитаемости и ремонтопригодности. Код нарушает многие правила.
Пустые строки
USB
над ним есть только одна пустая строка.
Пустые строки
Окружите определения функций и классов верхнего уровня двумя пустыми строками.
Длина линии
Максимальная длина строки
Ограничьте все строки до 79 символов.
Для потоковых длинных блоков текста с меньшим количеством структурных ограничений (строк документации или комментариев) длина строки должна быть ограничена 72 символами.
Есть много строк, которые содержат более 79 символов.
Константы
Похоже, что функция использует только одну константу: SECURITY_FILE
Константы
Константы обычно определяются на уровне модуля и пишутся заглавными буквами с подчеркиванием, разделяющим слова. Примеры включают
MAX_OVERFLOW
иTOTAL
.
Двигаться SECURITY_FILE
в верхнюю часть модуля. Хотя его, возможно, никогда не потребуется обновлять, если потребуется изменение, его будет легче найти, а не искать в файле.
1. Я не согласен с
wait_for_usb()
функция, потому что что, если usb был вставлен во время этой 2-секундной задержки перед следующей проверкой? Чтобы распознать его, потребуется немного больше времени (особенно на моем картофельном ПК, где окнам требуется больше времени для распознавания устройств), но моя версия попадает туда сразу же, когда подключается usb.— user394299
@ user394299 Я имею в виду, это 2 секунды, но если ждать слишком долго, вы можете либо полностью отказаться от сна, либо заставить его спать на меньшее время
— C.Nivs
Ожидания, которые занимают все ядро ЦП только для отслеживания изменений, обычно считаются ужасными. Полагаю, этого было бы достаточно для простой демонстрации кода в школе, но если бы я увидел это в производственном приложении, я бы очень плохо подумал об авторе. У компьютера есть другие дела; пользователи ненавидят, когда программа использует все ядро только для того, чтобы дождаться чего-то неподконтрольного ей. В идеале вы хотите зарегистрироваться в ОС для события, но если вы не можете, по крайней мере, сделайте паузу на полсекунды или более между проверками. Сведите к минимуму время процессора.
— Корродиас
@ user394299 На самом деле любая реализация ожидания USB плохая, так что они, вероятно, имеют в виду и то, и другое. Моя — это усовершенствование, позволяющее избежать ударов цикла по ЦП, что снижает производительность. Райндерин прав, есть способы сделать это лучше, чем качество продукции.
— C.Nivs
@ user394299 Оба неоптимальны, да, но ожидание некоторого времени между проверками значительно легче при использовании ресурсов, чем жесткий цикл. Я ожидаю, что лучшая производительность будет достигнута при регистрации обработчика событий вставки диска в Win32 API, но это ужасно сложно сделать в Python. В этом вопросе, кажется, есть некоторые подробности. stackoverflow.com/questions/38689090
— Корродиас
Показать 3 больше комментариев