Python'da aynı dosyada birden fazla sınıf olması uygun mudur?


18

Yıllarca Java ve PHP'den sonra yeni Python dünyasına geliyorum. Dilin kendisi oldukça basit olsa da, başımı saramadığım ve şimdiye kadar okuduğum çok sayıda belge ve öğreticide cevap bulamadığım bazı 'küçük' sorunlarla mücadele ediyorum. .

Deneyimli Python uygulayıcısı için, bu soru aptalca görünebilir, ancak gerçekten bir cevap istiyorum, böylece dil ile daha da ileri gidebilirim:

Java ve PHP'de ( kesinlikle gerekli olmamasına rağmen ), her birinin classkendi dosyasına yazılması beklenir , dosyanın adıclass en iyi yöntemdir.

Ama Python'da veya en azından kontrol ettiğim öğreticilerde, sorun değil , aynı dosyada birden fazla sınıfın .

Bu kural üretimde, konuşlandırmaya hazır kodda mı yoksa sadece eğitim amaçlı kodda kısalık amacıyla mı yapılıyor?

Yanıtlar:


13

Python'da aynı dosyada birden fazla sınıf olması uygun mudur?

Evet. Hem felsefi açıdan hem de pratik bir bakış açısından.

Python'da modüller, bellekte bir kez var olan bir ad alanıdır.

Dosya başına bir sınıf tanımlanmış olan aşağıdaki varsayımsal dizin yapısına sahip olduğumuzu varsayalım:

                    Defines
 abc/
 |-- callable.py    Callable
 |-- container.py   Container
 |-- hashable.py    Hashable
 |-- iterable.py    Iterable
 |-- iterator.py    Iterator
 |-- sized.py       Sized
 ... 19 more

Bu sınıfların tümü collectionsmodülde mevcuttur ve standart kütüphane modülünde (aslında toplam 25 adet) tanımlanmıştır._collections_abc.py

Burada _collections_abc.pyalternatif varsayımsal dizin yapısından daha üstün olduğunu düşündüğüm birkaç konu var .

  • Bu dosyalar alfabetik olarak sıralanmıştır. Bunları başka şekillerde sıralayabilirsiniz, ancak dosyaları semantik bağımlılıklara göre sıralayan bir özelliğin farkında değilim. _Collections_abc modül kaynağı bağımlılığa göre düzenlenir.
  • Patolojik olmayan durumlarda, hem modüller hem de sınıf tanımları, her biri bellekte bir kez meydana gelen singletonlardır. Modüllerin sınıflar üzerinde iki yönlü bir eşlemesi olacaktır - modülleri gereksiz kılar.
  • Artan dosya sayısı, sınıfları rahatça okumayı daha kolay hale getirir (basitleştiren bir IDE'niz yoksa) - araçsız insanlar için daha az erişilebilir hale getirir.

Bir ad alanı ve organizasyonel perspektiften istenen bulduğunuzda sınıf gruplarını farklı modüllere ayırmanız engelleniyor mu?

Hayır.

Gönderen Python Zen felsefesi ve onu büyüdü ve gelişti altında prensiplerini yansıtmaktadır:

İsim alanları harika bir fikirdir - hadi bunlardan daha fazlasını yapalım!

Ancak şunu da hatırlatırız:

Düz iç içe geçmişten daha iyidir.

Python inanılmaz temiz ve okunması kolay. Sizi okumanızı teşvik eder. Her ayrı sınıfı ayrı bir dosyaya koymak okumayı engeller. Bu Python'un temel felsefesine aykırıdır. Standart Kütüphanenin yapısına bakın, modüllerin büyük çoğunluğu paketler değil tek dosya modülleridir. Deyimsel Python kodunun CPython standart lib'iyle aynı tarzda yazıldığını size bildiririm.

İşte soyut temel sınıf modülünden gerçek kod . Dilde çeşitli soyut türlerin ifadesi için bir referans olarak kullanmayı seviyorum.

Bu sınıfların her birinin ayrı bir dosya gerektirdiğini söyleyebilir misiniz?

class Hashable:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __hash__(self):
        return 0

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Hashable:
            try:
                for B in C.__mro__:
                    if "__hash__" in B.__dict__:
                        if B.__dict__["__hash__"]:
                            return True
                        break
            except AttributeError:
                # Old-style class
                if getattr(C, "__hash__", None):
                    return True
        return NotImplemented


class Iterable:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __iter__(self):
        while False:
            yield None

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Iterable:
            if _hasattr(C, "__iter__"):
                return True
        return NotImplemented

Iterable.register(str)


class Iterator(Iterable):

    @abstractmethod
    def next(self):
        'Return the next item from the iterator. When exhausted, raise StopIteration'
        raise StopIteration

    def __iter__(self):
        return self

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Iterator:
            if _hasattr(C, "next") and _hasattr(C, "__iter__"):
                return True
        return NotImplemented


class Sized:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __len__(self):
        return 0

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Sized:
            if _hasattr(C, "__len__"):
                return True
        return NotImplemented


class Container:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __contains__(self, x):
        return False

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Container:
            if _hasattr(C, "__contains__"):
                return True
        return NotImplemented


class Callable:
    __metaclass__ = ABCMeta

    @abstractmethod
    def __call__(self, *args, **kwds):
        return False

    @classmethod
    def __subclasshook__(cls, C):
        if cls is Callable:
            if _hasattr(C, "__call__"):
                return True
        return NotImplemented

Her birinin kendi dosyası olmalı mı?

Umarım değildir.

Bu dosyalar sadece kod değildir, aynı zamanda Python'un semantiği ile ilgili belgelerdir.

Belki ortalama 10 ila 20 hattır. Başka bir 10 satır kod görmek için neden tamamen ayrı bir dosyaya gitmem gerekiyor? Bu çok pratik değildir. Ayrıca, her dosyada neredeyse aynı kazan plakası ithalatı olacak ve daha fazla kod satırı ekleyecektir.

Bir modül listesine bakmak yerine, tüm bu Soyut Temel Sınıfları bulabileceğim tek bir modül olduğunu bilmek oldukça yararlı buluyorum. Onları birbirleriyle bağlam içinde görmek onları daha iyi anlamama izin verir. Bir Yinelemenin Yinelenebilir Bir Olduğunu Gördüğümde , Bir Yinelemenin Neler Olduğunu Gözden Geçirerek Hızlıca Gözden Geçirebilirim.

Bazen birkaç kısa derse giriyorum. Zaman içinde büyümeleri gerekse bile dosyada kalırlar. Bazen olgun modüller 1000'den fazla kod satırına sahiptir. Ancak ctrl-f kolaydır ve bazı IDE'ler dosyanın anahatlarını görüntülemeyi kolaylaştırır - bu nedenle dosya ne kadar büyük olursa olsun, aradığınız nesneye veya yönteme hızla gidebilirsiniz.

Sonuç

Yönüm, Python bağlamında, ilgili ve anlamsal olarak benzer sınıf tanımlarını aynı dosyada tutmayı tercih etmektir. Dosya kullanışsız olacak kadar büyürse, yeniden düzenlemeyi düşünün.


1
Anladığım kadarıyla, aynı dosyada birden fazla sınıfın olmasının uygun olduğunu gönderdiğiniz kod sayesinde argümanı çok inandırıcı bulamıyorum. Örneğin, PHP'de sadece buna benzer kodu içeren bir dosyaya sahip olmak çok yaygındı:class SomeException extends \Exception {}
Olivier Malki

3
Farklı toplulukların farklı kodlama standartları vardır. Java kullanıcıları python'a bakar ve "neden dosya başına birden fazla sınıfa izin veriyor !?" der. Python kullanıcıları Java'ya bakar ve "neden her sınıfın kendi dosyasına sahip olmasını gerektirir !?" der. Çalıştığınız topluluğun stilini takip etmek en iyisidir.
Robotu Gort

Burada da kafam karıştı. Görünüşe göre cevabımla Python hakkında bazı şeyler yanlış anladım. Ancak bir sınıfa mümkün olduğunca çok yöntem eklemek için "düz iç içe olandan daha iyi" olur mu? Genel olarak uyum ve SRP ilkelerinin hala işlevsellikte birbiriyle yakından ilişkili sınıflar sağlayan modülleri tercih eden bir modüle uygulanacağını düşünürüm (bir modül tek bir sınıftan daha kaba bir paket konseptini modellediğinden, belki de birden fazla sınıftan daha fazlası) ), özellikle de herhangi bir modül kapsamı değişkeni (umarım genel olarak önlenmesine rağmen) kapsamda artacağından.

1
Python'un Zen'i, birbiriyle gergin olan ilkelerin bir listesidir. Birisi, “Seyrek yoğun olmaktan daha iyidir.” - "Düz yuvalanmışdan daha iyidir." Python Zen'in bireysel hatları kolayca yanlış kullanılabilir ve aşırı uçlara götürülebilir, ancak bir bütün olarak ele alındığında, makul insanların aksi takdirde katılmayabilecekleri kodlama ve ortak zemin bulma sanatına yardımcı olabilir. Ben insanlar benim kod örnekleri yoğun düşünün sanmıyorum, ama ne tarif bana çok yoğun geliyor.
Aaron Hall

Teşekkür ederim Jeffrey Albertson / Çizgi Roman Guy. :) Python kullanıcılarının çoğu (çift alt çizgi) özel yöntemleri kullanmamalıdır, ancak bir çekirdek tasarımcı / mimarın operatörleri, karşılaştırıcıları, alt simge gösterimini, bağlamları ve diğerlerini özel olarak kullanmak için meta programlamaya girmesine izin verirler. dil özellikleri. En az sürpriz ilkesini ihlal etmedikleri sürece, bence değer / zarar oranı sınırsızdır.
Aaron Hall

4

Uygulamanızı Python'da yapılandırırken, paketler ve modüller açısından düşünmeniz gerekir.

Modüller, bahsettiğiniz dosyalarla ilgilidir. Aynı modül içinde bir sürü derse sahip olmak iyidir. Amaç aynı modül içindeki tüm sınıfların aynı amaca / mantığa hizmet etmesidir. Modül çok uzun sürerse, mantığınızı yeniden tasarlayarak alt bölümlere ayırmayı düşünün.

Python Geliştirme Teklifleri Dizini hakkında zaman zaman okumayı unutmayın .


2

Bunun gerçek cevabı geneldir ve kullanılan dile bağlı değildir: Bir dosyada olması gereken şey, öncelikle kaç sınıfı tanımladığına bağlı değildir. Mantıksal bağlılığa ve karmaşıklığa bağlıdır. Dönemi.

Bu nedenle, birbirine bağlı birkaç çok küçük sınıfınız varsa, bunlar aynı dosyada paketlenmelidir. Başka bir sınıfa sıkıca bağlı değilse veya başka bir sınıfa eklenemeyecek kadar karmaşıksa bir sınıfı ayırmalısınız.

Bununla birlikte, dosya başına bir sınıf kuralı genellikle iyi bir sezgisel yöntemdir. Bununla birlikte, önemli istisnalar vardır: Yalnızca tek kullanıcı sınıfının uygulama detayı olan küçük bir yardımcı sınıf genellikle bu kullanıcı sınıfının dosyasına paketlenmelidir. Eğer üç sınıf var Aynı şekilde, vector2, vector3ve vector4, ayrı dosyalarda bunları uygulamak için muhtemel küçük bir sebep vardır.


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.