--Verbose veya -v seçeneği bir komut dosyasına nasıl uygulanır?


95

Birkaç araçtan --verboseveya -vbirkaç araçtan biliyorum ve bunu kendi komut dosyalarıma ve araçlarıma uygulamak istiyorum.

Yerleştirmeyi düşündüm:

if verbose:
    print ...

kaynak kodum aracılığıyla, böylece bir kullanıcı -vseçeneği geçerse , değişken verboseolarak ayarlanacak Trueve metin yazdırılacaktır.

Bu doğru yaklaşım mı yoksa daha yaygın bir yol var mı?

Ek: Argümanların ayrıştırılmasını gerçekleştirmenin bir yolunu istemiyorum. Nasıl yapıldığını bildiğimi. Ben sadece ayrıntılı seçenekle özellikle ilgileniyorum.


9
Neden günlüğe kaydetme modülünü kullanıp günlük düzeyini varsayılan olarak ayarlamıyorsunuz ve --verbose geçtiğinde DEBUG ayarlamıyorsunuz? Dilde mevcut olan hiçbir şeyi yeniden uygulamamak en iyisi ...
Tim

3
@Tim, katılıyorum, ancak kayıt modülü oldukça acı verici.
mlissner

Yanıtlar:


109

Benim önerim bir fonksiyon kullanmaktır. Ancak if, yapmak isteyebileceğiniz işlevi yerine koymak yerine , şu şekilde yapın:

if verbose:
    def verboseprint(*args):
        # Print each argument separately so caller doesn't need to
        # stuff everything to be printed into a single string
        for arg in args:
           print arg,
        print
else:   
    verboseprint = lambda *a: None      # do-nothing function

(Evet, bir ififadede bir işlev tanımlayabilirsiniz ve yalnızca koşul doğruysa tanımlanır!)

Python 3 kullanıyorsanız, burada printzaten bir işlev varsa (veya print2.x kullanarak bir işlev olarak kullanmak istiyorsanız from __future__ import print_function) daha da basit:

verboseprint = print if verbose else lambda *a, **k: None

Bu şekilde işlev, verbosebayrağı sürekli olarak test etmek yerine, ayrıntılı mod kapalıysa (bir lambda kullanarak) hiçbir şey yapmama olarak tanımlanır .

Kullanıcı , programınızın çalıştırılması sırasında ayrıntı modunu değiştirebilseydi , bu yanlış bir yaklaşım olacaktır ( ifişlevde olması gerekir ), ancak bir komut satırı bayrağıyla ayarladığınız için, yalnızca kararı bir kez ver.

Daha sonra örneğin verboseprint("look at all my verbosity!", object(), 3)bir "ayrıntılı" mesaj yazdırmak istediğinizde kullanın.


1
Daha da iyisi, bunu printişlev olarak yapın: Birçok argümanı kabul edin. print(*args)3.x ve for arg in args: print arg,2.x'de olduğu gibi uygulanabilir . Ana avantajı, açık strçağrılar / biçimlendirme ve birleştirme olmadan tek bir mesajda dizeleri ve diğer türlerdeki şeyleri karıştırmaya izin vermesidir .

print arg,Satırın sonunda virgül ne için kullanılır ?
SamK

Bu, kişinin kendisi için deneysel olarak veya belgeleri kontrol ederek kolayca belirlenir, ancak normalde yazdırılacak satır sonunu bastırır.
kindall

5
Python 3 yazdırma işlevi, yazdırma işlevini tam olarak yeniden üretmek için isteğe bağlı anahtar sözcük bağımsız değişkenini de alır:def verboseprint(*args, **kwargs): print(*args, **kwargs)
lstyls

67

loggingModülü kullanın :

import logging as log
…
args = p.parse_args()
if args.verbose:
    log.basicConfig(format="%(levelname)s: %(message)s", level=log.DEBUG)
    log.info("Verbose output.")
else:
    log.basicConfig(format="%(levelname)s: %(message)s")

log.info("This should be verbose.")
log.warning("This is a warning.")
log.error("This is an error.")

Bunların tümü otomatik olarak şu adrese gider stderr:

% python myprogram.py
WARNING: This is a warning.
ERROR: This is an error.

% python myprogram.py -v
INFO: Verbose output.
INFO: This should be verbose.
WARNING: This is a warning.
ERROR: This is an error.

Daha fazla bilgi için Python Belgelerine ve öğreticilere bakın .


8
Buradaki Python Dokümanlarına göre , günlük kaydı, yalnızca programın normal yürütülmesi sırasında çıktı yazdırmanız gereken durumlarda kullanılmamalıdır. Görünüşe göre OP'nin istediği bu.
SANDeveloper

1
Bu, temel sorun için iyi görünüyor, ancak birçok * nix komutu aynı zamanda birden fazla ayrıntı düzeyini de destekler (-v -v -v, vb.), Bu şekilde dağınık olabilir.
TextGeek

12

@ Kindall'ın yanıtını oluşturmak ve basitleştirmek, işte genellikle kullandığım şey:

v_print = None
def main()
    parser = argparse.ArgumentParser()
    parser.add_argument('-v', '--verbosity', action="count", 
                        help="increase output verbosity (e.g., -vv is more than -v)")

    args = parser.parse_args()

    if args.verbosity:
        def _v_print(*verb_args):
            if verb_args[0] > (3 - args.verbosity):
                print verb_args[1]  
    else:
        _v_print = lambda *a: None  # do-nothing function

    global v_print
    v_print = _v_print

if __name__ == '__main__':
    main()

Bu daha sonra komut dosyanız boyunca aşağıdaki kullanımı sağlar:

v_print(1, "INFO message")
v_print(2, "WARN message")
v_print(3, "ERROR message")

Ve senaryonuz şöyle çağrılabilir:

% python verbose-tester.py -v
ERROR message

% python verbose=tester.py -vv
WARN message
ERROR message

% python verbose-tester.py -vvv
INFO message
WARN message
ERROR message

Birkaç not:

  1. İlk argümanınız hata seviyeniz ve ikincisi mesajınızdır. 3Günlük kaydınızın üst sınırını belirleyen sihirli sayıya sahiptir , ancak bunu basitlik için bir uzlaşma olarak kabul ediyorum.
  2. v_printProgramınız boyunca çalışmak istiyorsanız , önemsiz şeyleri global ile yapmanız gerekir. Hiç eğlenceli değil, ama birine daha iyi bir yol bulması için meydan okuyorum.

1
INFO ve WARN için kayıt modülünü neden kullanmıyorsunuz? Bu, -vkullanıldığında onu içe aktarır. Mevcut çözümünüzde her şey stderr yerine stdout'a atılıyor. Ve: normalde her hatayı kullanıcıya iletmek istersiniz, değil mi?
Profpatsch

2
Evet, bu adil bir nokta. Günlüğe kaydetmenin kaçınmaya çalıştığım bazı bilişsel ek yükleri var, ama muhtemelen yapılacak "doğru" şey bu. Geçmişte sadece
canımı sıktı

9

Komut dosyalarımda yaptığım şey, çalışma zamanında 'ayrıntılı' seçeneğinin ayarlanıp ayarlanmadığını kontrol etmek ve ardından günlük düzeyimi hata ayıklama olarak ayarlamaktır. Ayarlanmamışsa, bilgi olarak ayarlıyorum. Bu şekilde kodunuzun her yerinde 'eğer ayrıntılı' kontroller yapmazsınız.


2

Sizin vprintiçin ayrıntılı bayrağı kontrol eden bir işleviniz varsa, diyelim ki, daha temiz olabilir . O zaman vprintisteğe bağlı ayrıntı istediğiniz herhangi bir yerde kendi işlevinizi çağırırsınız .



2

@ kindall'ın çözümü Python 3.5 sürümümle çalışmıyor. @styles, yorumunda, sebebin isteğe bağlı ek anahtar sözcükler argümanı olduğunu doğru bir şekilde belirtir . Dolayısıyla Python 3 için biraz iyileştirilmiş sürümüm şuna benziyor:

if VERBOSE:
    def verboseprint(*args, **kwargs):
        print(*args, **kwargs)
else:
    verboseprint = lambda *a, **k: None # do-nothing function

1

Programın ayrıntılı olup olmayacağı anlamına argparsegelen , muhtemelen from ile ayarlanan global bir değişken olabilir sys.argv. Daha sonra bir dekoratör, eğer ayrıntı açıksa, standart giriş, işlev çalıştığı sürece boş aygıta yönlendirilecek şekilde yazılabilir:

import os
from contextlib import redirect_stdout
verbose = False

def louder(f):
    def loud_f(*args, **kwargs):
        if not verbose:
            with open(os.devnull, 'w') as void:
                with redirect_stdout(void):
                    return f(*args, **kwargs)
        return f(*args, **kwargs)
    return loud_f

@louder
def foo(s):
    print(s*3)

foo("bar")

Bu cevap, bu koddan ilham almıştır ; aslında onu programımda bir modül olarak kullanacaktım, ancak anlayamadığım hatalar aldım, bu yüzden bir kısmını uyarladım.

Bu çözümün dezavantajı, loggingayrıntıların, programın ne kadar ayrıntılı olabileceğinin daha ince ayarına izin veren, bunun aksine ikili olmasıdır . Ayrıca, tüm print aramalar, istenmeyebilecek şekilde yönlendirilir.


0

İhtiyacım olan şey, bir nesneyi (obj) yazdıran bir işlevdir, ancak yalnızca genel değişken ayrıntılı doğruysa, aksi takdirde hiçbir şey yapmaz.

İstediğim zaman "ayrıntılı" genel parametresini değiştirebilmek istiyorum. Benim için basitlik ve okunabilirlik büyük önem taşıyor. Bu yüzden aşağıdaki satırların gösterdiği gibi devam edeceğim:

ak@HP2000:~$ python3
Python 3.4.3 (default, Oct 14 2015, 20:28:29) 
[GCC 4.8.4] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> verbose = True
>>> def vprint(obj):
...     if verbose:
...         print(obj)
...     return
... 
>>> vprint('Norm and I')
Norm and I
>>> verbose = False
>>> vprint('I and Norm')
>>> 

Global değişken "ayrıntılı" da parametre listesinden ayarlanabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.