Как передать функцию, список, среди прочего, как аргументы argparse в Python? - PullRequest
0 голосов
/ 25 апреля 2020

У меня есть следующий скрипт, который работает, и я пытаюсь избежать использования '__main__' внутри того же модуля:

def download():
    urls = \
        [
            'https://ipleak.net/json',
            'https://httpbin.org/get'
        ] * 4

    downloads = asyn.init_download(urls, "json")
    return downloads

def pprint_json(d):
    print(json.dumps(d, indent=4, sort_keys=True))

def multiprocess_list(n_pools, func, list):
    executor = concurrent.futures.ProcessPoolExecutor(n_pools)
    futures = [executor.submit(func, item) for item in list]
    concurrent.futures.wait(futures)

if __name__ == '__main__':
    multiprocess_list(4, pprint_json, download())

Функция download(), как видно из ее названия, загружает urls асинхронно с использованием asyncio и aiohttp.

Я хочу выполнить multiprocess_list из любого места «глобально»:

def multiprocess_list(n_pools, func, list):
    executor = concurrent.futures.ProcessPoolExecutor(n_pools)
    futures = [executor.submit(func, item) for item in list]
    concurrent.futures.wait(futures)

def main(args):
    parser = argparse.ArgumentParser(description="Multiprocessing a list.")
    parser.add_argument("-n", "--n_pools", type=int, required=True)
    parser.add_argument("-f", "--function", required=True)
    parser.add_argument("-l", "--list", required=True)
    args = parser.parse_args(args)

    multiprocess_list(args.n_pools, args.function, args.list)

if __name__ == '__main__':
    import sys
    main(sys.argv[1:])

Импортировать указанный выше модуль в любой другой файл python и, возможно, запустите его так: (хотя не работает)

def download():
    urls = \
        [
            'https://ipleak.net/json',
            'https://httpbin.org/get'
        ] * 4

    downloads = asyn.init_download(urls, "json")
    return downloads

def pprint_json(d):
    print(json.dumps(d, indent=4, sort_keys=True))

mp.main(["-n", 4, "-f", pprint_json, "-l", download()])

Это дает мне ошибку:

if not arg_string[0] in self.prefix_chars: TypeError: 'int' object is not subscriptable

Следовательно, передайте один аргумент как функцию для запуска, другой как список или функцию, которая возвращает список, например download().

  • Это можно сделать в python?
  • Если да, может кто-нибудь объяснить, как?
  • Мой подход правильный или я его полностью теряю?

NB : Мой переводчик использует Python3 .8, и я немного новичок в python, пожалуйста, потерпите меня немного.

1 Ответ

1 голос
/ 25 апреля 2020

Argparse ожидает список строк и может подавиться другими типами. Работает ли это, если вы цитируете 4?

mp.main(["-n", "4", "-f", pprint_json, "-l", download()])

pprint_json, и результат download() также должен быть строками для этой работы.

Этот подход создания замена argv не всегда сумасшедшая, но в вашем случае, зачем звонить main(), чтобы проанализировать ваши аргументы, если они у вас уже есть? Почему бы не вызвать multiprocess_list() напрямую с соответствующими аргументами?

Причина использования main() заключается в том, что в будущем я мог бы добавить больше функций, кроме multiprocess_list()

Затем вы можете вызывать их напрямую при вызове скрипта из Python, вместо создания другого аргумента для выбора одного из них. Вы все еще можете использовать main() для анализа аргументов из командной строки.

следующая ошибка TypeError: 'function' object is not subscriptable

Ах, это тоже не строка. В этом случае я не ожидаю, что это будет работать из командной строки. Вы уже так много работали?

Вы можете попробовать что-то вроде

mp.main(["-n", "4", "-f", "pprint_json", "-l", download()])

Но тогда main() должен каким-то образом интерпретировать это имя функции как функцию. Может быть что-то вроде

multiprocess_list(args.n_pools, getattr(foo, args.function), args.list)

, где foo - это модуль, в котором вы сохраняете выбираемые функции.

...