Как лучше всего вызывать одну и ту же функцию несколько раз? - PullRequest
0 голосов
/ 10 апреля 2020

Впервые до Python, и я пытаюсь написать что-то, что возьмет файлы, расположенные в разных каталогах, и разархивирует их (* .Z файлы). Я пытаюсь понять лучший способ сделать это без повторения кода, как показано ниже. Однако, кроме добавления одной и той же строки снова для каждого файла, может ли это быть каким-то образом зациклено для каждого имени файла? Например, один файл может находиться в /root/xxx/yyy.Z, другой /root/xxx/zzz.Z и /root/xxx/aaa.Z

Я могу запустить эту функцию с аргументами, указывающими на каждый каталог , но это кажется неуклюжим, но работает.

def UnzipFiles(pathtofile1,pathtofile2,pathtofile3):
    for filename in os.listdir(pathtofile1):
        if filename.endswith(".Z"): 
           retcode = subprocess.call(['gunzip', pathtofile1])
    else:
        if retcode != 0:
            raise IOError('unzipfiles exited with code %d' % retcode)

    for filename in os.listdir(pathtofile2):
        if filename.endswith(".Z"): 
           retcode = subprocess.call(['gunzip', pathtofile1])
    else:
        if retcode != 0:
            raise IOError('unzipfiles exited with code %d' % retcode)

    for filename in os.listdir(pathtofile3):
        if filename.endswith(".Z"): 
           retcode = subprocess.call(['gunzip', pathtofile3])
    else:
        if retcode != 0:
            raise IOError('unzipfiles exited with code %d' % retcode)

Я должен кое-что прояснить, чего не сделал в своем исходном посте. (1) Группы файлов .Z являются их собственным каталогом. Например, одна группа файлов находится в /root/xxx/yyy.Z, другая /root/yyy/zzz.Z и /root/aaa/aaa.Z. Таким образом, есть три различных каталога, которые мне нужно пролистать. И (2) приблизительно 20 или около того файлов распаковываются. И эта деятельность будет происходить в лучшем случае ежемесячно.

Ответы [ 3 ]

0 голосов
/ 10 апреля 2020

Вы можете использовать функцию zip в python для итерации 3 переменных одновременно

def UnzipFiles(pathtofile1,pathtofile2,pathtofile3):
    for filename1,filename2,filename3 in zip(os.listdir(pathtofile1),os.listdir(pathtofile2),os.listdir(pathtofile3)):
        if filename1.endswith(".Z"): 
            retcode1 = subprocess.call(['gunzip', pathtofile1])
        else:
            if retcode1 != 0:
               raise IOError('unzipfiles exited with code %d' % retcode1)
        if filename2.endswith(".Z"): 
            retcode2 = subprocess.call(['gunzip', pathtofile2])
        else:
            if retcode2 != 0:
               raise IOError('unzipfiles exited with code %d' % retcode2)
        if filename3.endswith(".Z"): 
            retcode3 = subprocess.call(['gunzip', pathtofile3])
        else:
           if retcode3 != 0:
               raise IOError('unzipfiles exited with code %d' % retcode3)

По сути это одно и то же

0 голосов
/ 10 апреля 2020

Кажется преждевременным превращать это в функцию - он жестко запрограммирован для работы только с 3 «файловыми» параметрами, и даже если он модифицирован как один параметр, он все равно привязан к расширению ".Z". Это делает его по существу полезным только для одной ультраспецифической задачи c: распаковка точно 3 файлов (действительно каталогов ...) с конкретным расширением c.

Кроме того, кажется, что существует путаница между каталогами и путями к файлам; os.listdir извлекает все файлы в каталоге, что, кажется, противоречит тому, как вы назвали свои переменные, что предполагает, что вы передаете пути к файлам.

В любом случае, вы можете удалить несколько блоков в своей функции и передать в папку root путь, или, наоборот, пропустить os.listdir и указать прямой единственный путь к subprocess.call.

Я бы предложил написать встроенный код:

for path in os.listdir('/root/xxx/'):
    if path.endswith('.Z') and ret := subprocess.call(['gunzip', path]):
        raise IOError(f'gunzip exited with code {ret} on {path}')

Если вы действительно делаете это так часто, что для вызывающего абонента это слишком много, вы можете использовать:

def unzip_all(directory, extension='.Z'):
    for path in os.listdir(directory):
        if path.endswith(extension) and ret := subprocess.call(['gunzip', path]):
            raise IOError(f'gunzip exited with code {ret} on {path}')

И если вы хотите извлечь только 3 указанных c файла вместо 3 указанных c каталогов:

for path in ['root/xxx/foo.Z', 'root/xxx/bar.Z', 'root/xxx/baz.Z']:
    if ret := subprocess.call(['gunzip', path]):
        raise IOError(f'gunzip exited with code {ret} on {path}')

Поскольку gunzip принимает несколько аргументов, вы можете воспользоваться что все сводится к следующему:

paths = ['root/xxx/foo.Z', 'root/xxx/bar.Z', 'root/xxx/baz.Z']

if ret := subprocess.call(['gunzip'] + paths):
    raise IOError(f'gunzip exited with code {ret} on {paths}')

Обратите внимание, что здесь используется синтаксис присваивания усов := в Python 3.8.

В качестве отступления,

else:
    if:
        ....

- более сложный способ написания

elif:
    ....

Я рекомендую следовать PEP-8 ; функции должны быть lower_camel_case. UpperCamelCase зарезервировано для классов.

0 голосов
/ 10 апреля 2020

Просто измените свой код для 1 входного файла и проверьте os walk (), после этого вы можете передать список файлов, используя map()

results = list(map(UnzipFiles, [list of files]))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...