Tek satırlık fonksiyonlardan oluşan veri munging boru hatları için birim testi


10

Mary Rose Cook'un Fonksiyonel Programlamaya Pratik Girişini okurken, bir anti-desen örneği veriyor

def format_bands(bands):
    for band in bands:
        band['country'] = 'Canada'
        band['name'] = band['name'].replace('.', '')
        band['name'] = band['name'].title()

dan beri

  • işlev birden fazla şey yapar
  • isim açıklayıcı değil
  • yan etkileri var

Önerilen bir çözüm olarak, anonim işlevlerin ardışık düzenini önermektedir

pipeline_each(bands, [call(lambda x: 'Canada', 'country'),
                      call(lambda x: x.replace('.', ''), 'name'),
                      call(str.title, 'name')])

Ancak bu bana daha az test edilebilir olmanın dezavantajına sahip gibi geliyor; en azından format_bands, bunun ne anlama geldiğini kontrol etmek için bir birim testine sahip olabilir, ancak boru hattını nasıl test edebilirim? Yoksa anonim işlevlerin test edilmesine gerek kalmayacak kadar açıklayıcı olduğu fikri mi?

Bunun için gerçek dünyadaki uygulama pandaskodumu daha işlevsel hale getirmeye çalışıyor . Sık sık bir "munging" fonksiyonu içinde bir tür boru hattım olacak

def munge_data(df)
     df['name'] = df['name'].str.lower()
     df = df.drop_duplicates()
     return df

Veya ardışık düzen tarzında yeniden yazma:

def munge_data(df)
    munged = (df.assign(lambda x: x['name'].str.lower()
                .drop_duplicates())
    return munged

Böyle bir durumda en iyi uygulamalar için herhangi bir öneriniz var mı?


4
Bu bağımsız lambda fonksiyonları ünite testi için çok küçük. Nihai sonucu test edin. Başka bir deyişle, anonim işlevler birim test edilemez, bu yüzden tek tek test etmeyi planlıyorsanız işlevi anonim bir işlev olarak yazmayın.
Robert Harvey

Yanıtlar:


1

Sanırım kitabın düzeltilmiş örneğinin muhtemelen daha önemli kısmını kaçırdınız. Koddaki en temel değişiklik, bir listedeki tüm değerlerde çalışan yöntemden tek bir öğe üzerinde çalışmaya kadar.

Listedeki tüm öğeler üzerinde belirli bir işlemi gerçekleştiren iter(bu durumda adlı pipeline_foreach) gibi işlevler zaten vardır . Bunu bir fordöngü ile çoğaltmaya gerek yoktu . Ayrıca iyi bilinen bir liste işlemi kullanmak niyetinizi netleştirir. İle mapdeğerleri dönüştürüyor. İle iterher bir öğenin bir yan etkiye gerçekleştiriyorsunuz. İle forsen döngü bunun bakmak kadar ... şey, gerçekten bilmiyorum.

Düzeltilmiş örnek kod hala çok işlevsel değil, çünkü (anlatabildiğim kadarıyla) listedeki değerleri döndürmeden değiştirir, daha fazla boru veya işlev kompozisyonu önler. İşlevsel olarak tercih edilen yöntem map, güncellenmiş countryve ile yeni bir grup listesi oluşturur name. Daha sonra bu çıkışı bir sonraki işleve bağlayabilir veya mapbir grup listesi alan başka bir işlevle oluşturabilirsiniz . İle iter, bir boru hattı çıkmaz gibi.

Sonuç sonucu kodu burada test rahatsız için çok küçük olan küçük fonksiyonları olduğunu düşünüyorum. Sonuçta, replaceveya karşısında birim testleri yazmanız gerekmez title. Şimdi belki bunları birlikte kendi fonksiyonunuzda oluşturmak ve istediğiniz kombinasyonun tek bir öğe üzerinde elde edildiğini test etmek istersiniz. Ben ise, muhtemelen sadece değişmiş olurdu format_bandsiçin format_bandtekil, döngü için düştü ve denir pipeline_each(bands, format_band). Ardından, bir şeyi unutmadığınızdan emin olmak için format_band'ı test edebilirsiniz.

Her neyse, kodunuza devam edin. İkinci kod örneğiniz daha fazla boru hattı-y gibi görünüyor. Ancak bu tek başına fonksiyonel programlamanın faydalarını sağlamaz. Pratikte fonksiyonel programlama, sadece giriş ve çıkışları açısından uyumluluklarını tanımlayarak fonksiyonların diğer fonksiyonlarla uyumluluğunu sağlamak anlamına gelir. İşlev içinde gizli yan etkiler varsa, giriş / çıkış diğer işlevlerle sıralı olmasına rağmen, çalışma süresine kadar uyumlu olup olmadıklarını bilemezsiniz. Bununla birlikte, iki işlev yan etkisizdir ve çıktıyı girdiye eşleştirirse , beklenmedik sonuçlardan endişe duyarak bunları sıralayabilir veya oluşturabilirsiniz .

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.