2016-05-27 2 views
1

я использую arparse в Python для разбора аргументов из командной строки:Попутных вокруг разобранных аргументов не делают никакого удовольствия

def main(): 
    parser = argparse.ArgumentParser(usage=usage) 
    parser.add_argument('-v', '--verbose', dest='verbose', action='store_true') 
    parser.add_argument(...) 
    args = parser.parse_args() 

Я использую объект args только в нескольких местах коды.

Есть три метода и стек вызовов выглядит следующим образом

def first_level(args): 
    second_level() 

def second_level(): 
    third_level() 

def third_level(): 
    ### here I want to add some logging if args.verbose is True 

Я хочу, чтобы добавить некоторое протоколирование в third_level().

Я не хочу менять подпись метода second_level().

Как я могу сделать arg объект в third_lelvel()?

Я мог бы хранить arg в качестве глобальной переменной, но мне сказали, чтобы не использовать глобальные переменные в разработчика тренингов несколько лет назад ....

Что такое общий способ справиться с этим?

+0

Не выполняйте регистрацию в своем 'third_level (..)'. Используйте 'if args.verbose: logging.setLevel (logging.INFO)' вместо этого. – SuperSaiyan

+0

Я бы только передал объект 'args' первой функции. Если другим нужны значения из него, я передам их как значения в сигнатуре функции, чтобы дать понять, что им нужно. Назовите их «second_level (verbose = args.verbose)» и т. Д. – Ben

ответ

2

Преобразование моего комментария для ответа. Я бы предложил не состояние в вашем third_level(..). Существуют механизмы, позволяющие блоку регистрации заботиться об этом - и эти механизмы можно контролировать из-за пределов этих трех функций.

Что-то вроде:

def first_level(args): 
    second_level() 

def second_level(): 
    third_level() 

def third_level(): 
    logging.info("log line which will be printed if logging is at INFO level") 


def main(): 
    args = .... 
    #Set the logging level, conditionally 
    if args.verbose: 
     logging.basicConfig(filename='myapp.log', level=logging.INFO) 
    else: 
     logging.basicConfig(filename='myapp.log', level=logging.WARNING) 

    first_level(args) 
+0

Да, вы правы. Для этого случая лучше всего использовать регистрацию. Если доступ к args.foo для разных целей, то требуется другое решение. Но это другой вопрос ... – guettli

+0

Я, вероятно, буду обернуть три функции в классе (если это имеет смысл) и установить переменную внутри объекта, третья функция может использовать ее как: 'self.variable' – SuperSaiyan

2

общей структура модуля что-то вроде:

imports ... 
<constants> 
options = {verbose=0, etc} 
# alt options = argparse.Namespace(logging=False,....) 

def levelone(args, **kwargs): 
    .... 
def leveltwo(...): 

def levelthree(...): 
    <use constant> 
    <use options> 

def parser(): 
    p = argparse.ArgumentParser() 
    .... 
    args = p.parse_args() # this uses sys.argv 

if __name__=='__main__': 
     args = parser() 
     options.update(vars(args)) 
     levelone(args) 

Корпуса модуля имеет определение функций, и может быть импортирован другим модулем. Если используется как сценарий, то parser читает командную строку. Этот глобальный options доступен для всех видов state как параметры. В смысле это константы, которые пользователь или модуль импорта могут настроить. Значения, импортированные из файла config, могут иметь одинаковую роль.

Другой распространенный шаблон - это сделать ваши методы функций класса и передать args в качестве атрибутов объекта.

class Foo(): 
    def __init__(self, logging=False): 
     self.logging = logging 
    def levelone(): 
    def leveltwo(): 
     <use self.logging> 
foo(args.logging).levelone() 

Хотя globals обескураживают, это больше, потому что они злоупотребляют, и портить модульность, что функции обеспечивают. Но Python также предоставляет пространство имен уровня module, которое может содержать больше, чем просто функции и классы. И любая функция, определенная в модуле, может получить доступ к этому пространству имен, если только его собственные определения не теневые.

var1 = 'module level variable' 
var2 = 'another' 
def foo(var3): 
    x = var1 # read/use var1 
    var2 = 1 # shadow the module level definition 
    etc 

================

Я не уверен, что я должен рекомендовать это или нет, но можно разобрать sys.argv в third_level.

def third_level(): 
    import argparse 
    p = argparse.ArgumentParser() 
    p.add_argument('-v','--verbose',action='count') 
    args = p.parse_known_args() 
    verbose = args.verbose 
    <logging> 

argparse импорта sys и использует sys.argv.Он может сделать это независимо от того, используется ли он на уровне вашего скрипта, в вашем main или вложенной функции. logging делает такой же вещь. Вы можете использовать свой собственный импортированный модуль, чтобы скрытно передавать значения в функции. Очевидно, что можно злоупотреблять. A class с атрибутами класса также можно использовать таким образом.

Смежные вопросы