파이썬에서 같은 파일에 여러 클래스를 두는 것이 괜찮습니까?


18

나는 수년간의 Java와 PHP 후에 파이썬 세계에 새로 왔습니다. 언어 자체는 매우 간단하지만, 나는 머리를 감쌀 수없는 몇 가지 '사소한'문제로 어려움을 겪고 있습니다. .

숙련 된 Python 실무자에게는이 질문이 어리석은 것처럼 보일 수 있지만, 이에 대한 답변을 원하므로 언어를 더 발전시킬 수 있습니다.

Java 및 PHP ( 엄격히 요구되지는 않지만 )에서는 class파일 이름을 class가장 좋은 방법으로 자체 파일에 각각 작성 해야 합니다.

그러나 파이썬에서, 또는 내가 확인한 튜토리얼에서 적어도 그것입니다 확인 동일한 파일에 여러 수업을 할 수 있습니다.

이 규칙이 프로덕션, 배포 준비 코드에서 유지됩니까? 아니면 교육 전용 코드에서 간결성을 위해 수행 되었습니까?

답변:


13

파이썬에서 같은 파일에 여러 클래스를 두는 것이 괜찮습니까?

예. 철학적 관점과 실제적인 관점에서 모두.

파이썬에서 모듈은 메모리에 한 번 존재하는 네임 스페이스입니다.

파일 당 하나의 클래스가 정의 된 다음과 같은 가상 디렉토리 구조가 있다고 가정하십시오.

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

이러한 모든 클래스는 collections모듈 에서 사용 가능 하며 표준 라이브러리 모듈에서 정의 된 (실제로 총 25 개)_collections_abc.py

여기 _collections_abc.py에는 대체 가상 디렉토리 구조보다 우수 하다고 생각되는 몇 가지 문제가 있습니다 .

  • 이러한 파일은 알파벳순으로 정렬됩니다. 다른 방법으로 정렬 할 수는 있지만 시맨틱 종속성별로 파일을 정렬하는 기능을 알지 못합니다. _collections_abc 모듈 소스는 종속성별로 구성됩니다.
  • 비 병리학적인 경우, 모듈과 클래스 정의는 모두 메모리에서 한 번 발생하는 싱글 톤입니다. 모듈을 클래스에 양도 적으로 매핑하면 모듈이 중복됩니다.
  • 파일 수가 증가하면 클래스를 통해 읽기가 편리하지 않습니다 (단순하게 IDE를 사용하지 않는 한).

이름 공간과 조직적 관점에서 클래스 그룹을 다른 모듈로 나누지 못하게 되었습니까?

아니.

파이썬선에서 , 그것은 성장하고 진화하는 철학과 원칙을 반영합니다.

네임 스페이스는 훌륭한 아이디어 중 하나입니다. 더 많은 것을 해보자!

그러나 다음과 같이 말합니다.

평평한 것이 중첩보다 낫습니다.

파이썬은 매우 깨끗하고 읽기 쉽습니다. 그것은 당신이 그것을 읽을 것을 권장합니다. 모든 개별 수업을 별도의 파일에 넣으면 읽기가 권장되지 않습니다. 이것은 파이썬의 핵심 철학에 위배됩니다. 표준 라이브러리 의 구조를 살펴보십시오. 대다수의 모듈은 패키지가 아닌 단일 파일 모듈입니다. 관용적 인 파이썬 코드는 CPython 표준 라이브러리와 같은 스타일로 작성되었다고 여러분에게 제출하겠습니다.

다음은 추상 기본 클래스 모듈 의 실제 코드입니다 . 언어에서 다양한 추상 유형을 나타내는 데 참조로 사용하고 싶습니다.

이 클래스들 각각에 별도의 파일이 필요하다고 말 하시겠습니까?

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

그래서 그들은 각자 자신의 파일을 가져야합니까?

내가하지 희망.

이 파일들은 코드가 아니라 파이썬의 의미에 대한 문서입니다.

평균 10 ~ 20 줄입니다. 다른 10 줄의 코드를 보려면 완전히 별도의 파일로 이동해야하는 이유는 무엇입니까? 그것은 비현실적입니다. 또한 각 파일에 거의 동일한 상용구 가져 오기가있어 중복 된 코드 줄이 추가됩니다.

모듈 목록을 살펴 보지 않고 이러한 추상 기본 클래스를 모두 찾을 수있는 단일 모듈이 있다는 것을 아는 것이 매우 유용합니다. 서로의 맥락에서 그것들을 보면 그것들을 더 잘 이해할 수 있습니다. Iterator Iterable 이라는 것을 알게되면 , Iterable이 무엇을 구성하는지 빠르게 살펴볼 수 있습니다.

나는 때때로 두 개의 매우 짧은 수업을하게됩니다. 그들은 시간이 지남에 따라 커져야하더라도 파일에 남아 있습니다. 성숙한 모듈에는 때로는 1000 줄 이상의 코드가 있습니다. 그러나 ctrl-f는 쉽고, 일부 IDE에서는 파일의 개요를 쉽게 볼 수 있습니다. 따라서 파일의 크기에 관계없이 원하는 객체 나 방법으로 빠르게 이동할 수 있습니다.

결론

파이썬의 맥락에서 내 지시는 관련적이고 의미 론적으로 유사한 클래스 정의를 동일한 파일에 유지하는 것을 선호하는 것입니다. 파일이 다루기 어려워 질 정도로 커지면 재구성을 고려하십시오.


1
글쎄, 당신이 제출 한 코드 덕분에 동일한 파일에 여러 클래스를 갖는 것이 좋다는 주장 때문에 매우 설득력있는 주장을 찾을 수는 없습니다. 예를 들어, PHP에서 다음과 유사한 코드 만있는 전체 파일을 갖는 것이 매우 일반적입니다.class SomeException extends \Exception {}
Olivier Malki

3
지역 사회마다 코딩 표준이 다릅니다. Java 사람들은 파이썬을보고 "파일 당 여러 클래스를 허용하는 이유는 무엇입니까?"라고 말합니다. 파이썬 사람들은 Java를보고 "각 클래스마다 고유 한 파일이 필요합니다!"라고 말합니다. 작업중인 커뮤니티의 스타일을 따르는 것이 가장 좋습니다.
로봇 Gort

나도 여기 혼란스러워. 분명히 나는 ​​내 대답으로 파이썬에 대해 몇 가지 오해를했다. 그러나 클래스에 가능한 많은 메소드를 추가하기 위해 "플랫이 중첩보다 낫다"를 적용합니까? 일반적으로 응집력과 SRP의 원리는 기능면에서 서로 밀접하게 관련된 클래스를 제공하는 모듈을 선호하는 모듈에 여전히 적용된다고 생각합니다. ), 특히 모든 모듈 범위 변수 (일반적으로 피할 수는 있지만)의 범위가 증가하기 때문에.

1
파이썬의 선은 서로 긴장을 풀고있는 원리들의 목록입니다. "스파 스는 밀도보다 낫다"라는 요점에 동의 할 것이다. -바로 다음에 "평면이 중첩보다 낫습니다." 파이썬의 선 (Zen of Python)의 개별 라인은 쉽게 오용 될 수 있고 극단적으로 받아 들여질 수 있지만, 전체적으로 볼 때, 합리적인 사람들이 달리 동의하지 않을 수있는 공통된 기반을 찾고 코딩하는 기술을 도울 수 있습니다. 사람들이 내 코드 예제를 밀도가 있다고 생각하지는 않지만 설명하는 것은 매우 밀도가 높습니다.
Aaron Hall

Jeffrey Albertson / Comic Book Guy에게 감사합니다. :) 대부분의 Python 사용자는 (밑줄) 특수 메소드를 사용하지 않아야하지만 핵심 디자이너 / 건축가는 메타 프로그래밍에 참여하여 연산자, 비교기, 아래 첨자 표기법, 컨텍스트 및 기타를 사용자 정의 할 수 있습니다. 언어 기능. 그들이 최저 놀람의 원칙을 위반하지 않는 한, 가치 대 피해 비율은 무한대라고 생각합니다.
Aaron Hall

4

파이썬으로 애플리케이션을 구조화 할 때 패키지와 모듈의 관점에서 생각해야합니다.

모듈은 당신이 말하는 파일에 관한 것입니다. 동일한 모듈 내에 많은 클래스를 갖는 것이 좋습니다. 동일한 모듈 내의 모든 클래스는 동일한 목적 / 논리를 제공해야합니다. 모듈이 너무 길면 로직을 다시 디자인하여 세분화하는 것을 고려하십시오.

Index of Python Enhancement Proposals에 대해 수시로 읽으십시오 .


2

이것에 대한 실제 대답은 일반적이며 사용되는 언어에 의존하지 않습니다. 파일에 있어야하는 것은 주로 정의하는 클래스 수에 의존하지 않습니다. 논리적 연결성과 복잡성에 따라 다릅니다. 기간.

따라서 상호 연결된 매우 작은 클래스가 몇 개있는 경우 동일한 파일에 번들로 묶어야합니다. 클래스가 다른 클래스에 단단히 연결되어 있지 않거나 다른 클래스에 포함하기에 너무 복잡한 경우 클래스를 분리해야합니다.

즉, 파일 당 하나의 규칙은 일반적으로 좋은 휴리스틱입니다. 그러나 중요한 예외가 있습니다. 실제로 유일한 사용자 클래스의 구현 세부 사항 인 작은 도우미 클래스는 일반적으로 해당 사용자 클래스 파일에 번들로 묶어야합니다. 당신은 세 가지 클래스가있는 경우 마찬가지로 vector2, vector3vector4, 별도의 파일을 구현하는 가능성이 작은 이유가있다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.