Python'da ne zaman ders kullanmalıyım?


177

Yaklaşık iki yıldır python programlıyorum; çoğunlukla veri şeyler (pandalar, mpl, numpy), aynı zamanda otomasyon komut dosyaları ve küçük web uygulamaları. Daha iyi bir programcı olmaya çalışıyorum ve python bilgimi artırıyorum ve beni rahatsız eden şeylerden biri hiç bir sınıf kullanmadım (küçük web uygulamaları için rastgele şişe kodu kopyalama dışında). Genelde ne olduklarını anlıyorum, ama basit bir fonksiyon üzerinde neden onlara ihtiyaç duyacağımı kafamda dolamıyorum.

Soruma özgüllük eklemek için: Her zaman birden fazla veri kaynağından (mongo, sql, postgres, apis) veri çekmeyi, çok veya biraz veri munging ve biçimlendirmeyi, verileri csv / excel'e yazmayı içeren tonlarca otomatik rapor yazıyorum. / html, e-postayla gönderin. Komut dosyaları ~ 250 satır ile ~ 600 satır arasında değişir. Bunu yapmak için sınıfları kullanmamın bir sebebi var mı ve neden?


15
Eğer kodunuzu daha güzel yönetebilirseniz, hiçbir sınıfla kodlamak yanlış bir şey yoktur. OOP programcıları, dil tasarımındaki kısıtlamalar veya farklı kalıpların yüzeysel olarak anlaşılması nedeniyle sorunları abartma eğilimindedir.
Jason Hu

Yanıtlar:


133

Sınıflar, Nesneye Yönelik Programlamanın temel direğidir . OOP, kod organizasyonu, yeniden kullanılabilirlik ve kapsülleme ile son derece ilgilidir.

İlk olarak, bir feragatname: OOP kısmen Fonksiyonel Programlama'nın aksine Python'da çok kullanılan farklı bir paradigma olan . Python'da (veya elbette çoğu dilde) program yapan herkes OOP kullanmaz. Java 8'de çok Nesneye Dayalı olmayan çok şey yapabilirsiniz. OOP kullanmak istemiyorsanız, kullanmayın. Bir daha asla kullanmayacağınız verileri işlemek için tek seferlik komut dosyaları yazıyorsanız, istediğiniz gibi yazmaya devam edin.

Bununla birlikte, OOP kullanmak için birçok neden vardır.

Bazı nedenler:

  • Organizasyon: OOP, koddaki hem verileri hem de prosedürü tanımlamanın ve tanımlamanın iyi bilinen ve standart yollarını tanımlar. Hem veriler hem de prosedürler farklı tanım seviyelerinde (farklı sınıflarda) saklanabilir ve bu tanımlar hakkında konuşmak için standart yollar vardır. Yani, OOP'yi standart bir şekilde kullanırsanız, daha sonra kendinizin ve başkalarının kodunuzu anlamasına, düzenlemesine ve kullanmasına yardımcı olur. Ayrıca, karmaşık, keyfi bir veri depolama mekanizması (dikte veya liste dikleri veya dikte veya set dikleri listesi veya herhangi bir şey) kullanmak yerine, veri yapılarının parçalarını adlandırabilir ve bunlara rahatça başvurabilirsiniz.

  • Durum: OOP, durumu tanımlamanıza ve takip etmenize yardımcı olur. Örneğin, klasik bir örnekte, öğrencileri işleyen bir program oluşturuyorsanız (örneğin, bir not programı), onlar hakkında ihtiyacınız olan tüm bilgileri tek bir yerde (ad, yaş, cinsiyet, sınıf seviyesi, dersler, notlar, öğretmenler, akranlar, diyet, özel ihtiyaçlar, vb.) ve nesne canlı olduğu ve kolayca erişilebilir olduğu sürece bu veriler devam eder.

  • Kapsülleme : Kapsülleme ile prosedür ve veriler birlikte saklanır. Yöntemler (işlevler için bir OOP terimi), üzerinde çalıştıkları ve ürettikleri verilerin yanında tanımlanır. Erişim kontrolüne izin veren Java gibi bir dilde veya genel API'nizi nasıl tanımladığınıza bağlı olarak Python'da, bu yöntem ve verilerin kullanıcıdan gizlenebileceği anlamına gelir. Bunun anlamı, koda ihtiyacınız varsa veya değiştirmek istiyorsanız, kodun uygulanması için ne isterseniz yapabilirsiniz, ancak genel API'leri aynı tutabilirsiniz.

  • Kalıtım : Kalıtım, verileri ve prosedürü tek bir yerde (bir sınıfta) tanımlamanıza ve daha sonra bu işlevselliği geçersiz kılmanıza veya genişletmenize olanak tanır. Örneğin, Python'da sık sık dictek işlevler eklemek için insanların sınıfın alt sınıflarını oluşturduğunu görüyorum . Bilinmeyen bir anahtara göre varsayılan bir değer vermek için var olmayan bir sözlükten bir anahtar istendiğinde, ortak bir değişiklik kural dışı durum atan yöntemi geçersiz kılar. Bu, şimdi veya daha sonra kendi kodunuzu genişletmenize, başkalarının kodunuzu genişletmesine izin verir ve diğer kişilerin kodunu genişletmenize izin verir.

  • Yeniden kullanılabilirlik: Tüm bu nedenler ve diğerleri, kodun daha fazla yeniden kullanılabilirliğine izin verir. Nesneye yönelik kod, katı (test edilmiş) kodu bir kez yazmanıza ve ardından tekrar tekrar kullanmanıza olanak tanır. Özel kullanım durumunuz için bir şey yapmanız gerekiyorsa, mevcut bir sınıftan devralınabilir ve mevcut davranışın üzerine yazabilirsiniz. Bir şeyi değiştirmeniz gerekiyorsa, mevcut genel yöntem imzalarını korurken hepsini değiştirebilirsiniz ve kimse daha akıllı değildir (umarım).

Yine, OOP'yi kullanmamanın birkaç nedeni var ve buna gerek yok. Ama neyse ki Python gibi bir dille, sadece biraz veya çok kullanabilirsiniz, size kalmış.

Öğrenci kullanım örneği (kod kalitesi garantisi yok, sadece bir örnek):

Nesne odaklı

class Student(object):
    def __init__(self, name, age, gender, level, grades=None):
        self.name = name
        self.age = age
        self.gender = gender
        self.level = level
        self.grades = grades or {}

    def setGrade(self, course, grade):
        self.grades[course] = grade

    def getGrade(self, course):
        return self.grades[course]

    def getGPA(self):
        return sum(self.grades.values())/len(self.grades)

# Define some students
john = Student("John", 12, "male", 6, {"math":3.3})
jane = Student("Jane", 12, "female", 6, {"math":3.5})

# Now we can get to the grades easily
print(john.getGPA())
print(jane.getGPA())

Standart Dict

def calculateGPA(gradeDict):
    return sum(gradeDict.values())/len(gradeDict)

students = {}
# We can set the keys to variables so we might minimize typos
name, age, gender, level, grades = "name", "age", "gender", "level", "grades"
john, jane = "john", "jane"
math = "math"
students[john] = {}
students[john][age] = 12
students[john][gender] = "male"
students[john][level] = 6
students[john][grades] = {math:3.3}

students[jane] = {}
students[jane][age] = 12
students[jane][gender] = "female"
students[jane][level] = 6
students[jane][grades] = {math:3.5}

# At this point, we need to remember who the students are and where the grades are stored. Not a huge deal, but avoided by OOP.
print(calculateGPA(students[john][grades]))
print(calculateGPA(students[jane][grades]))

"Verim" nedeniyle Python kapsülleme genellikle jeneratörler ve bağlam yöneticileri ile sınıflardan daha temizdir.
Dmitry Rubanovich

4
@meter Bir örnek ekledim. Umut ediyorum bu yardım eder. Buradaki not, doğru isme sahip diktatörlerinizin anahtarlarına güvenmek yerine, Python yorumlayıcısının sizi karıştırır ve tanımlı yöntemleri (Java ve diğer olmasa da) tanımlanmış alanları kullanmaya zorlarsanız bu kısıtlamayı sizin için yapar. OOP dilleri Python gibi sınıfların dışındaki alanları tanımlamanıza izin vermez)).
dantiston

5
@meter da, bir kapsülleme örneği olarak: diyelim ki bugün bu uygulama gayet iyi, çünkü üniversitemde sadece bir kez 50.000 öğrenciye not ortalaması almam gerekiyor. Şimdi yarın bir hibe alıyoruz ve her öğrencinin mevcut genel not ortalamasını her saniyede vermeliyiz (elbette, kimse bunu istemez, ancak bunu sadece hesaplama açısından zorlaştırmak için). Daha sonra GPA'yı "belleğe alabilir" ve yalnızca değiştiğinde (örneğin, setGrade yönteminde bir değişken ayarlayarak) hesaplayabiliriz, diğerleri önbelleğe alınmış bir sürümü döndürür. Kullanıcı hala getGPA () yöntemini kullanıyor ancak uygulama değişti.
dantiston

4
@dantiston, bu örnekte collections.namedtuple gerekir. Yeni bir tür oluşturabilirsiniz Student = collections.namedtuple ("Öğrenci", "ad, yaş, cinsiyet, seviye, notlar"). Ve sonra john = Student ("John", 12, "male", grades = {'math': 3.5}, level = 6) örnekleri oluşturabilirsiniz. Sınıf oluştururken yaptığınız gibi hem konumsal hem de adlandırılmış bağımsız değişkenleri kullandığınıza dikkat edin. Bu, Python'da sizin için zaten uygulanmış bir veri türüdür. Daha sonra grubun ilk elemanını almak için john [0] veya john.name'ye başvurabilirsiniz. Artık john'un notlarını john.grades.values ​​() olarak alabilirsiniz. Ve zaten sizin için yapıldı.
Dmitry Rubanovich

2
benim için kapsülleme her zaman OOP kullanmak için yeterince iyi bir nedendir. Değeri makul boyutlu herhangi bir kodlama projesi için OOP kullanmak DEĞİL görmek için mücadele. Sanırım ters sorunun
San Jay

23

Fonksiyonlarınızın durumunu korumanız gerektiğinde ve jeneratörlerle (dönüşten ziyade verim sağlayan fonksiyonlar) gerçekleştirilemediğinde. Jeneratörler kendi durumlarını korurlar.

Standart operatörlerden herhangi birini geçersiz kılmak istiyorsanız bir sınıfa ihtiyacınız vardır.

Bir Ziyaretçi kalıbı için her kullanımınızda sınıflara ihtiyacınız olacaktır. Diğer tüm tasarım modelleri, jeneratörler, bağlam yöneticileri (sınıflar olarak jeneratörler olarak da daha iyi uygulanır) ve POD türleri (sözlükler, listeler ve tuples, vb.) İle daha etkili ve temiz bir şekilde gerçekleştirilebilir.

"Pythonic" kodu yazmak istiyorsanız, sınıf yerine bağlam yöneticilerini ve oluşturucuları tercih etmelisiniz. Daha temiz olacak.

İşlevselliği genişletmek istiyorsanız, bunu neredeyse her zaman mirastan ziyade içerme ile gerçekleştirebileceksiniz.

Her kuralda olduğu gibi, bunun bir istisnası vardır. İşlevselliği hızlı bir şekilde kapsüllemek istiyorsanız (örneğin, kitaplık düzeyinde yeniden kullanılabilir kod yerine test kodu yazın), durumu bir sınıfta kapsülleyebilirsiniz. Basit olacak ve tekrar kullanılabilir olması gerekmeyecek.

C ++ tarzı bir yıkıcıya (RIIA) ihtiyacınız varsa, kesinlikle sınıfları kullanmak istemezsiniz. İçerik yöneticileri istiyorsunuz.


1
@DmitryRubanovich kapanışları Python'daki jeneratörler aracılığıyla uygulanmaz.
Eli Korvigo

1
@DmitryRubanovich, "kapanışlar Python'da jeneratörler olarak uygulandı" anlamına geliyordu, bu doğru değil. Kapaklar çok daha esnektir. Oluşturucular bir Generatorörneği (özel bir yineleyici) döndürmekle yükümlüdürler, ancak kapanmaların herhangi bir imzası olabilir. Temelde kapaklar oluşturarak sınıflardan kaçınabilirsiniz. Ve kapanışlar sadece "diğer fonksiyonlar bağlamında tanımlanan fonksiyonlar" değildir.
Eli Korvigo

3
@Eli Korvigo, aslında, jeneratörler sözdizimsel olarak önemli bir sıçramadır. Bir kuyruğun soyutlamasını, işlevler yığının soyutlamaları gibi oluştururlar. Ve çoğu veri akışı yığın / kuyruk ilkellerinden birleştirilebilir.
Dmitry Rubanovich

1
@DmitryRubanovich burada elma ve portakaldan bahsediyoruz. Diyorum ki, jeneratörler çok sınırlı sayıda durumda faydalıdır ve hiçbir şekilde genel amaçlı durumsal callables'in yerine geçemez. Puanlarımla çelişmeden bana ne kadar harika olduklarını söylüyorsun.
Eli Korvigo

1
@Eli Korvigo, ve diyorum ki callables sadece fonksiyonların genellemesidir. Hangi kendileri yığınların işlenmesi üzerinde sözdizimsel şeker. Jeneratörler kuyrukların işlenmesi üzerine sözdizimsel şekerdir. Ancak sözdizimindeki bu gelişme, daha karmaşık yapıların daha kolay ve daha açık sözdizimiyle oluşturulmasına izin verir. '.next ()' neredeyse hiç kullanılmaz, btw.
Dmitry Rubanovich

11

Bence doğru yapıyorsun. Sınıflar, bazı iş mantığını veya zor ilişkilere sahip zor gerçek yaşam süreçlerini simüle etmeniz gerektiğinde makul olur. Örnek olarak:

  • Paylaşım durumu olan çeşitli işlevler
  • Aynı durum değişkenlerinin birden fazla kopyası
  • Mevcut bir işlevin davranışını genişletmek için

Ayrıca bu klasik videoyu izlemenizi öneririm


3
Python'da geri çağrı işlevi kalıcı bir duruma ihtiyaç duyduğunda sınıf kullanmaya gerek yoktur. Dönüş yerine Python'un verimini kullanmak bir işlevi yeniden etkinleştirir.
Dmitry Rubanovich

4

Bir sınıf gerçek dünya varlığını tanımlar. Bireysel olarak var olan ve diğerlerinden ayrı kendi mantığı olan bir şey üzerinde çalışıyorsanız, bunun için bir sınıf oluşturmanız gerekir. Örneğin, veritabanı bağlantısını kapsülleyen bir sınıf.

Bu durumda, sınıf oluşturmaya gerek yok


0

Fikir ve tasarımınıza bağlıdır. OOP'lardan daha iyi bir tasarımcıysanız, doğal olarak çeşitli tasarım desenleri şeklinde ortaya çıkacaktır. Basit bir komut dosyası düzeyinde işlem için OOP'ler ek yük olabilir. Basit, yeniden kullanılabilir ve genişletilebilir gibi OOP'lerin temel faydalarını göz önünde bulundurun ve gerekli olup olmadıklarından emin olun. OOP'lar karmaşık şeyleri daha basit ve daha basit hale getirir. OOP'ları kullanarak veya OOP'ları kullanmamak her şeyi basit bir şekilde tutar. ki bunu daha basit kullanın.

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.