Python'da ördek yazma, veri doğrulama ve iddialı programlama


10

Hakkında ördek yazarak :

Ördek yazmaya, yöntem ve işlev gövdelerindeki bağımsız değişken türlerini alışkanlık olarak sınamayarak, belgelere, açık koda ve doğru kullanımı sağlamak için sınanmaya dayanarak yardım edilir.

Argüman validasyonu hakkında (EAFP: Bağışlama izni istemekten daha kolaydır). Buradan uyarlanmış bir örnek :

... daha pitonik olduğu düşünülüyor:

def my_method(self, key):
    try:
        value = self.a_dict[member]
    except TypeError:
        # do something else

Bu, kodunuzu kullanan herkesin gerçek bir sözlük veya alt sınıf kullanması gerekmediği anlamına gelir - eşleme arabirimini uygulayan herhangi bir nesneyi kullanabilirler.

Ne yazık ki pratikte bu kadar basit değil. Yukarıdaki örnekteki üye bir tam sayı olabilirse ne olur? Tamsayılar değişmezdir, bu yüzden bunları sözlük anahtarı olarak kullanmak son derece mantıklıdır. Bununla birlikte, sıra tipi nesneleri indekslemek için de kullanılırlar. Üye bir tamsayı olursa, ikinci örnek, sözlüklerin yanı sıra listeler ve dizeler aracılığıyla da izin verebilir.

Hakkında iddialı programlama:

İddialar, bir programın dahili durumunun, programcı tarafından beklendiği gibi, hataları yakalamak amacıyla kontrol edilmesinin sistematik bir yoludur. Özellikle, kod yazılırken yapılan yanlış varsayımları yakalamak veya başka bir programcı tarafından bir arabirimi kötüye kullanmak için iyidirler. Buna ek olarak, programcının varsayımlarını açıkça göstererek bir dereceye kadar hat içi dokümantasyon görevi görebilirler. ("Açık, örtük olmaktan iyidir.")

Bahsedilen kavramlar bazen çatışıyor, bu yüzden herhangi bir veri doğrulaması yapmıyorum, güçlü doğrulama veya ekleme yaparsanız seçerken aşağıdaki faktörlere güveniyorum:

  1. Güçlü doğrulama. Güçlü doğrulama ile, özel bir İstisna oluşturmak ( ApiErrorörneğin) demek istiyorum . İşlevim / yöntemim genel bir API'nın parçasıysa, beklenmedik tür hakkında iyi bir hata iletisi göstermek için bağımsız değişkeni doğrulamak daha iyidir. Türü kontrol ederek sadece kullanmak demek değil isinstance, aynı zamanda geçilen nesne gerekli arayüzü destekliyorsa (ördek yazarak). API'yi belgeleyip beklenen türü belirtirken kullanıcı işlevimi beklenmedik bir şekilde kullanmak isteyebilir, ancak varsayımları kontrol ettiğimde daha güvende hissediyorum. Genellikle kullanırım isinstanceve daha sonra diğer türleri veya ördekleri desteklemek istersem, doğrulama mantığını değiştiririm.

  2. İddialı programlama. Kodum yeni ise, ben çok ekler kullanın. Bu konudaki tavsiyeleriniz neler? Daha sonra koddaki ekleri kaldırır mısınız?

  3. Eğer benim fonksiyonum / metodum bir API'nin bir parçası değilse de, benim argümanlarımızdan bazılarını yazılmamış, incelenmemiş veya benim tarafımdan test edilmemiş başka bir koda geçirirse, çağrılan arayüze göre çok fazla varsayım yaparım. Bunun arkasındaki mantığım - kodumda daha iyi başarısız olur, daha sonra bir yerde 10 kat daha derin ve çok fazla hata ayıklamak ve daha sonra yine de koduma iddia eklemek için zorlar anlaşılmaz bir hata ile stacktrace derin.

Tür / değer doğrulamasının ne zaman kullanılacağına veya kullanılamayacağına ilişkin yorum ve öneriler, iddia ediyor mu? Sorunun en iyi formülasyonu için üzgünüm.

Örneğin, CustomerSQLAlchemy bildirim modelinin bulunduğu aşağıdaki işlevi göz önünde bulundurun :

def add_customer(self, customer):
    """Save new customer into the database.
    @param customer: Customer instance, whose id is None
    @return: merged into global session customer
    """
    # no validation here at all
    # let's hope SQLAlchemy session will break if `customer` is not a model instance
    customer = self.session.add(customer)
    self.session.commit()
    return customer

Dolayısıyla, doğrulamayı ele almanın birkaç yolu vardır:

def add_customer(self, customer):
    # this is an API method, so let's validate the input
    if not isinstance(customer, Customer):
        raise ApiError('Invalid type')
    if customer.id is not None:
        raise ApiError('id should be None')

    customer = self.session.add(customer)
    self.session.commit()
    return customer

veya

def add_customer(self, customer):
    # this is an internal method, but i want to be sure
    # that it's a customer model instance
    assert isinstance(customer, Customer), 'Achtung!'
    assert customer.id is None

    customer = self.session.add(customer)
    self.session.commit()
    return customer

Bunların her birini ördek yazma, tip kontrolü, veri doğrulama bağlamında ne zaman ve neden kullanacaksınız?


1
performans nedenlerinden ötürü tıpkı ünite testleri gibi ölçümleri çıkarmamalısınız
Bryan Chen

Yanıtlar:


4

Bazı yol gösterici ilkeler vereyim.

İlke # 1. Http://docs.python.org/2/reference/simple_stmts.html dosyasında belirtildiği gibi , hata ayıklama için hala oradayken, eklerin performans yükü bir komut satırı seçeneğiyle kaldırılabilir. Performans bir sorunsa, bunu yapın. Ekleri bırakın. (Ama iddialarda önemli bir şey yapmayın!)

İlke # 2. Bir şey iddia ediyorsanız ve önemli bir hatayla karşılaşırsanız, bir iddia kullanın. Başka bir şey yapmanın kesinlikle bir değeri yoktur. Daha sonra birisi bunu değiştirmek isterse, kodunuzu değiştirebilir veya bu yöntem çağrısından kaçınabilir.

İlke # 3. Sadece aptalca bir şey olduğunu düşündüğünüz için bir şeye izin vermeyin. Peki ya yönteminiz dizelere izin veriyorsa? Çalışırsa çalışır.

İlke # 4. Olası hataların işareti olan şeylere izin verme. Örneğin, bir seçenek sözlüğü geçirmeyi düşünün. Bu sözlük geçerli seçenekler olmayan şeyler içeriyorsa, bu, birisinin API'nizi anlamadığını veya başka bir yazım hatası olduğunu gösteren bir işarettir. Bunu patlatmak, bir yazım hatasını yakalama olasılığının, birisinin makul bir şey yapmasını engellemekten daha olasıdır.

İlk 2 prensibe dayanarak, ikinci versiyonunuz atılabilir. Diğer ikisinden hangisini tercih ederseniz bir lezzet meselesi. Hangisinin daha muhtemel olduğunu düşünüyorsun? Birinin müşteri olmayan bir kişiye geçeceği add_customerve bazı şeylerin kesileceği (bu durumda sürüm 3 tercih edilir) veya birisinin müşterinizi bir noktada, doğru yöntemlerin tümüne yanıt veren bir tür proxy nesnesiyle değiştirmek isteyeceği (bu durumda sürüm 1 tercih edilir).

Şahsen her iki hata modunu da gördüm. Tembel olduğum ve daha az yazarak genel ilkeden sürüm 1 ile gitme eğilimindeyim. (Ayrıca bu tür bir başarısızlık genellikle er ya da geç oldukça açık bir şekilde ortaya çıkma eğilimindedir. Ve bir proxy nesnesi kullanmak istediğimde, ellerimi bağlayan insanlara gerçekten rahatsız oluyorum.) Ama kime saygı duyduğum programcılar var diğer tarafa giderdim.


Özellikle arayüz tasarlarken yeni sınıflar ve yöntemler yazarken v.3'ü tercih ederim. Ayrıca benim kod diğerleri için yeni çünkü v.3 API yöntemleri için yararlı düşünün. İddialı yaklaşımın iyi bir uzlaşma olduğunu düşünüyorum, çünkü optimize edilmiş modda çalışırken üretimde kaldırılıyor. > Üfleme, bir yazım hatasını yakalama olasılığının, birisinin makul bir şey yapmasını engellemekten daha olasıdır. <Öyleyse böyle bir onay almanın sakıncası yok mu?
warvariuc

Bunu böyle koyalım. Kalıtımın tasarımları geliştirmeyi nasıl sevdiğimle eşleşmediğini düşünüyorum. Kompozisyonu tercih ederim. Bu yüzden bunun bu sınıfta olması gerektiğini iddia etmekten çekiniyorum. Ama bana bir şeyleri kurtardıklarını düşündüğüm iddialara karşı değilim.
btilly
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.