2012-02-23 36 views
5

komut satırı seçenekleri (argparse, Getopt, blargs, vs) ayrıştırma ve koordine etmek için birçok Python modülü vardır. Ve Python, çeşitli işlev argümanlarını (örneğin, varsayılan değerler, * varargs, ** keyword_args) işlemek için iyi yerleşik özellikler/deyimlerle kutsanmıştır. Ancak, üst düzey işlevler için çeşitli projelerin kodunu okurken, komut satırı argümanlarından çok daha az disiplin ve işlev argümanlarının standardizasyonunu görüyorum. Basit işlevler içinİşlev Argüman İşleme için Önerilen Python Modülleri?

, bu bir sorun değildir; yerleşik argüman özellikleri harika çalışır ve fazlasıyla yeterlidir. Ama onlar argüman karmaşıklığını yani üst düzey fonksiyonlar vb (tamamlayıcı veya münhasır bazı) farklı argümanlar ve seçenekler, farklı çalışma modları, aşırı sürmek varsayılan, bir sürü sağlar işlevsel zengin modüllerin .-- çok şey var orada komut satırı argümanlarına yaklaşıyor. Ve onlar büyük ölçüde kendi argümanlarını ad hoc yollarla hallediyor gibi görünüyor. komut satırı işleme sayısı göz önüne alındığında

orada modülleri ve bunlar zamanla kadar ne kadar rafine, Karmaşığım fonksiyon argümanları çekişme basitleştirilmesi için en az birkaç modülleri beklersiniz. Ancak PyPi, stackoverflow ve Google’ı başarı olmadan aradım. Öyleyse tavsiye edeceğiniz fonksiyonlar (komut satırı değil!) Argüman işleme modülleri var mı?

--- örnekle güncelleme ---

Bu kullanım durumu size sofistike bir modül ile uğraşıyoruz kadar görünmez çünkü gerçekten basit somut örnek vermek zor. Ancak, koddaki problemi açıklamak için bir çekim: Biçimlendirici örneğinde geçersiz kılınabilen veya işlev/yöntem çağrıldığında varsayılan bir biçimlendirici modül. Sadece birkaç seçenek olan için, orada seçenek işleme şişirme çok şey zaten var ve seçenek adları bıktıracak tekrarlanır. API bunun size geçirildi seçenekleri işlemek için bazı modülü kullanmak daha kolay olacağını düşünüyorum kadar karmaşık olursa

defaults = { 'indent':  4, 
       'prefix': None, 
       'suffix': None, 
       'name':  'aFormatter', 
       'reverse': False, 
       'show_name': False 
      } 

class Formatter(object): 

    def __init__(self, **kwargs): 
     self.name = kwargs.get('name', defaults['name']) 
     self.indent = kwargs.get('indent', defaults['indent']) 
     self.prefix = kwargs.get('prefix', defaults['prefix']) 
     self.suffix = kwargs.get('suffix', defaults['suffix']) 
     self.reverse = kwargs.get('reverse', defaults['reverse']) 
     self.show_name = kwargs.get('show_name', defaults['show_name']) 

    def show_lower(self, *args, **kwargs): 
     indent = kwargs.get('indent', self.indent) or 0 
     prefix = kwargs.get('prefix', self.prefix) 
     suffix = kwargs.get('suffix', self.suffix) 
     reverse = kwargs.get('reverse', self.reverse) 
     show_name = kwargs.get('show_name', self.show_name) 

     strings = [] 
     if show_name: 
      strings.append(self.name + ": ") 
     if indent: 
      strings.append(" " * indent) 
     if prefix: 
      strings.append(prefix) 
     for a in args: 
      strings.append(a.upper() if reverse else a.lower()) 
     if suffix: 
      strings.append(suffix) 
     print ''.join(strings) 

if __name__ == '__main__': 
    fmt = Formatter() 
    fmt.show_lower("THIS IS GOOD") 
    fmt.show_lower("THIS", "IS", "GOOD") 
    fmt.show_lower('this IS good', reverse=True) 
    fmt.show_lower("something!", show_name=True) 

    upper = Formatter(reverse=True) 
    upper.show_lower("this is good!") 
    upper.show_lower("and so is this!", reverse=False) 
+0

def somefunc hakkında konuşuyorsunuz (requiredValue, optionalValue = None, * args, ** kwargs)?Eğer işleyişinizi bu şekilde kodlarsanız, tıpkı bir terminalden gelen komut satırı işlemlerini (bir fonksiyonun kendisi) ele alacağınız gibi. – platinummonkey

+3

Karmaşık bir arabirime sahip bir işlev örneği ve bir kitaplıktan ne gibi basitleştirmeler beklediğinize dair bir fikir verebilir misiniz? (Değeri için, orada oldukça korkunç işlev arayüzleri olan bazı Python modülleri olduğunu düşünüyorum. Bunları kendiniz gibi yapmaya çalışmak yerine caydırıcı örnekler olarak düşünmenizi öneririm.) –

+0

@SvenMarnach Gerçekten son derece dikkatli Orada tüm maliyetlerden kaçının! Ancak, bir fonksiyon (fabrika fonksiyonunu söyleyin), karmaşık bir kabiliyet için giriş noktasıysa, karmaşık olması mutlaka bir hata değildir. Sadece işin karmaşıklığını/değişkenliğini yansıtabilir. –

cevap

1

, sizin API basitleştirmek için fiili çözümdür iyi bir şans var. Bazı modüller şeyleri çağırmak için çok karmaşık yollara sahip olmaları bir utanç değil, bir özelliktir.

3

Sorunuzu ilk okuduğumda, kendime bir bant yardım modülü sorduğunuzu ve bunun, hiç kimsenin kötü tasarımın devam etmesini sağlayan bir modül yazmak istemediğinden kaynaklanmadığını düşündüm.

Ama durum bundan daha karmaşık olduğunu fark etti. Tanımladığınız gibi bir modül oluşturma noktası, yeniden kullanılabilir, genel durum kodu oluşturmaktır. Şimdi, haklı olarak karmaşık olan bazı arayüzler de olabilir. Ancak bu arayüzler kesinlikle olup genel durum koduyla kolayca işlenemeyen arabirimlerdir. Bunlar karmaşıktır, çünkü birçok özel durumla sorun alanlarını ele alırlar.

Başka bir deyişle, arabirimi gerçekten yeniden ayarlanamazsa, büyük olasılıkla bir modülde genelleştirmeye değecek kadar önceden tahmin edilemeyecek kadar çok sayıda özel, özel durum kodu gerektirir. Tersine, eğer bir arayüz tanımladığınız türden bir modül ile kolayca örtülebilirse, o zaman muhtemelen aynı zamanda refactored de olabilir - bu durumda olması gerekir.

+0

Kabul etmiyorum. Bu argümanı takiben, komut satırı işlemenin argparse, getopt, vs.'ye genellenmesi mantıklı olmaz. Ama öyle. Benim istediğim, modüller ve fonksiyonlar için analog: karmaşık fonksiyonları genelleştiren ve basitleştiren kod - uygun olduğunda ve bazen de öyle - aynı şekilde argparse komutlara yardımcı olur. PyPi'deki kod okumam, bu kullanımın basitleştirilmesini önerir. Ve bu imkansız değil - iyi bir çalışma çözümüm var. Sadece daha fazla kabul edilen caddeler var mı diye bakıyorum. Çok fazla "sadece refactor!" cevaplar, sanırım yok. Oysa. –

+0

@JonathanEunice, ben hiç imkansız olduğunu söylemedim. Az önce belirtmek gerekirse, haklı olarak karmaşık kodların karmaşıklığını azaltmanın değil, artmasının muhtemel olduğunu söyledim. Daha genel olarak, komut satırı arabirimleri ve API'ler arasındaki benzetmenin yanlış olduğunu düşünüyorum. Gerçekten çok benzer değiller. – senderle

+0

IMO derece değil, bir fark. Komut satırları ve işlevleri, her biri belirli bir seçenekler, talimatlar ve veriler kümesi ile bazı işlevleri çağırır. Mutlu bir şekilde, işlevler genellikle daha basit ve daha fazla refactorable. Ancak PyPi'den gördüğüm kod, fonksiyonların basitleştirilmesine hala ihtiyaç olduğunu gösteriyor. YMMV. –

0

geliştiricinin elinde Onun, ancak bazı diğer projeler için yararlı olabilir ya da diğer kullanıcı arasında yayınlanacak bir kütüphane yapıyorsanız, o zaman sorunu belirlemeye ve bunu analiz gereken ilk düşünüyorum

İşlevlerinizi iyi belgeleyin, numaralı argüman sayısını en aza indirgemek, kullanıcıların tam olarak neye ihtiyaç duyduğunu belirtmek için sorun yaşayabilecekleri işlevsel argümanlar için varsayılan değerler sağlar.

ve bazı karmaşık gereksinimler için gelişmiş programlama için geçersiz kılınabilir özel classmethods sağlayabilir veya gerçekten kitaplık ile çaldıklarını gerçekleştirmek isteyen ileri düzey kullanıcılar tarafından, kalıtım her zaman vardır.

ve ayrıca PEP8 okuyabilir hangi may yararlı ama nihai hedefi, bağımsız değişken asgari sayısını belirtmek gerekli argümanları girmelerini kısıtlamak için, onun isteğe bağlı bağımsız değişkenler için varsayılan değerler sağlamak için iyi - o şekilde library/code, sıradan geliştiriciler tarafından da kolayca anlaşılabilir ...

0

Varsayılan değerler için daha genel bir kod yazabilirsiniz.

Eğer başka bir yoldan varsayılanı varsayılan olarak düşünürseniz, varsayılanları gözden geçirin ve eğer mevcut değilse anahtar kelimelerin üzerine yazarak.

defaults = { 'indent':  4, 
      'prefix': None, 
      'suffix': None, 
      'name':  'aFormatter', 
      'reverse': False, 
      'show_name': False 
     } 

class Formatter(object): 

    def __init__(self, **kwargs): 
     for d,dv in defaults.iteritems(): 
     kwargs[d] = kwargs.get(d, dv) 

Yan Not: Ben varsayılanlarla __init__ yöntem tanımında anahtar args kullanarak öneriyoruz. Bu function tanım gerçekten komut satırı ayrıştırma ve fonksiyon argümanı işleme çok ortak noktası var sanmıyorum senin sınıfın diğer geliştiriciler ve kullanıcılar (Formatter)

def __init__(self, indent=4, reverse=False .....etc.....): 
+0

kwargs [d] = kwargs.get (d, dv) 'kwargs.setdefault (d, dv)' olarak yazılabilir. Bu yüzden 'setdefault() 'olarak adlandırılır - henüz bir değer ayarlanmamışsa, varsayılan değerdir. –

2
  1. sözleşme haline verir. Komut satırı ile ilgili temel sorun, tek mevcut veri yapısının düz bir dizge listesi olması ve her dizenin ne anlama geldiğini tanımlamak için bir fonksiyon başlığı gibi bir aletin olmamasıdır. Bir Python işlevinin başlığında, her bir parametreye isimler verebilirsiniz, kapsayıcıları parametre olarak kabul edebilir, varsayılan argüman değerlerini tanımlayabilirsiniz. Komut satırı ayrıştırma kütüphanesi ne yapıyor? özellikler Python, fonksiyon çağrıları için sunar: parametrelere isim vermek, varsayılan değerleri atamak, istenen türlere dönüştürmek vb. Python'da, tüm bu özellikler yerleşiktir, bu nedenle kolaylık sağlamak için bir kütüphaneye ihtiyacınız yoktur.

  2. Örneğinizle ilgili olarak, dilin sunduğu özellikler kullanılarak bu tasarımın nasıl geliştirilebileceğinin çeşitli yolları vardır. defaults sözlüğünün yerine varsayılan argüman değerlerini kullanabilirsiniz, FormatterConfig sınıfındaki tüm bayrakları kapsülleyebilir ve sadece bu argümanların yerine tekrar tekrar tek bir argüman iletebilirsiniz. Ama sadece örnek kodda verdiğiniz arayüzü tam olarak istediğinizi varsayalım. Python argüman işlenmesiyle ilgili bu tür yapmak için birçok araç sunmaktadır

    class Config(dict): 
        def __init__(self, config): 
         dict.__init__(self, config) 
         self.__dict__ = self 
    
    def get_config(kwargs, defaults): 
        config = defaults.copy() 
        config.update(kwargs) 
        return Config(config) 
    
    class Formatter(object): 
    
        def __init__(self, **kwargs): 
         self.config = get_config(kwargs, defaults) 
    
        def show_lower(self, *args, **kwargs): 
         config = get_config(kwargs, self.config) 
    
         strings = [] 
         if config.show_name: 
          strings.append(config.name + ": ") 
         strings.append(" " * config.indent) 
         if config.prefix: 
          strings.append(config.prefix) 
         for a in args: 
          strings.append(a.upper() if config.reverse else a.lower()) 
         if config.suffix: 
          strings.append(config.suffix) 
         print "".join(strings) 
    

    : Bunu başarmanın bir yolu aşağıdaki kod olacaktır. Dolayısıyla, bazılarını (varsayılan argümanlar gibi) kullanmayacağımıza karar versek bile, kendimizi çok fazla tekrar etmekten kaçınabiliriz.

+0

Nokta 1: Evet! Güzel koydu. Python işlevleri, komut satırı argümanlarının düz dizelerinden çok daha zengin başlar. Nokta 2: Concur. Config/get_config bir modülde olsaydı, tam olarak ne istediğimin iyi bir başlangıcı olurdu ... Python args'ine kadar uzanan konfigürasyon varsayılanları, geçersiz kılmalar, vb. son derece opsiyonlu fonksiyonları destekler. Şimdilik PyPi'de cilalanmış, iyi bilinen bir modül yok. –

İlgili konular