Python 이름의 단일 및 이중 밑줄 I

2024. 1. 28. 18:38python/intermediate

Python에는 단일 또는 이중 밑줄 문자( ) 사용을 기반으로 하는 몇 가지 중요한 명명 규칙이 있습니다 . 이러한 규칙을 사용하면 API에서 공개 이름과 비공개 이름을 구별하고, 서브클래싱 목적으로 안전한 클래스를 작성하고, 이름 충돌을 방지하는 등의 작업을 수행할 수 있습니다._

이러한 규칙을 따르고 존중하면, 다른 Python 개발자의 눈에는 Python처럼 보이고, 일관되게 보이는 코드를 작성할 수 있습니다. 이 기술은 다른 개발자가 함께 작업할 수 있는 코드를 작성할 때 특히 유용합니다.

이 튜토리얼에서는 다음을 수행합니다.

밑줄 ( ) 사용에 의존하는 Python 명명 규칙 에 대해 알아봅니다._ 단일 선행 밑줄을 사용하여 공개 이름 과 비공개 이름을 구분합니다 . Python 클래스에서 이름 맹글링을 활용하려면 이중 선행 밑줄을 사용하세요. Python 이름에서 밑줄의 다른 일반적인 용도 살펴보기 입니다.

Python의 공용 인터페이스 및 명명 규칙

Python 프로그래머로서 여러분은 공개 인터페이스 나 API(애플리케이션 프로그래밍 인터페이스)를 사용하여 작업하는 경우가 많습니다 . API는 프로그램의 다른 부분이나 다른 프로그램에 서비스를 제공하는 일종의 프로그래밍 인터페이스입니다.

예를 들어 Python 표준 라이브러리에는 특정 서비스를 제공하는 많은 모듈과 패키지가 있습니다. 이러한 모듈과 패키지를 사용하려면 클래스, 함수, 변수, 상수, 모듈과 같은 공용 구성 요소 에 액세스해야 합니다 . 이러한 개체는 모두 모듈이나 패키지의 공개 인터페이스의 일부입니다. 코드에서 직접 사용할 수 있습니다.

그러나 이러한 패키지와 모듈 중 다수는 직접 액세스용이 아닌 개체를 정의합니다. 이러한 개체는 특정 패키지 또는 모듈의 내부 용도로만 사용됩니다. 이는 공개 인터페이스의 일부가 아닙니다.

Python 이름의 단일 및 이중 밑줄 Python 이름의 단일 및 이중 밑줄 레오 다니스 포조 라모스 2023년 11월 29일 댓글 1개 모범 사례 중급 파이썬 공유하다 공유하다 이메일 목차

Python의 공용 인터페이스 및 명명 규칙 Python 이름의 단일 선행 밑줄 Python에서 공개 및 비공개 이름 만들기 Python에서 공개 이름과 비공개 이름 사용 모듈 및 패키지의 공개 및 비공개 이름 내부 변수 및 상수 도우미 기능 비공개 모듈 와일드카드 가져오기 및 비공개 이름 비공개 회원이 포함된 수업 비공개 속성 비공개 방법 클래스의 이중 선행 밑줄: Python의 이름 맹글링 이름 맹글링 이해 상속에서 이름 맹글링 사용 Python 이름의 후행 밑줄 Python의 던더 이름 Python에서 밑줄의 다른 사용법 결론 광고를 제거하다 Python에는 단일 또는 이중 밑줄 문자( ) 사용을 기반으로 하는 몇 가지 중요한 명명 규칙이 있습니다 . 이러한 규칙을 사용하면 API에서 공개 이름과 비공개 이름을 구별하고, 서브클래싱 목적으로 안전한 클래스를 작성하고, 이름 충돌을 방지하는 등의 작업을 수행할 수 있습니다._

이러한 규칙을 따르고 존중하면 다른 Python 개발자의 눈에는 Python처럼 보이고 일관되게 보이는 코드를 작성할 수 있습니다. 이 기술은 다른 개발자가 함께 작업할 수 있는 코드를 작성할 때 특히 유용합니다.

이 튜토리얼에서는 다음을 수행합니다.

밑줄 ( ) 사용에 의존하는 Python 명명 규칙 에 대해 알아봅니다._ 단일 선행 밑줄을 사용하여 공개 이름 과 비공개 이름을 구분합니다 . Python 클래스에서 이름 맹글링을 활용하려면 이중 선행 밑줄을 사용하세요. Python 이름에서 밑줄의 다른 일반적인 용도 살펴보기 이 튜토리얼을 최대한 활용하려면 Python 변수 , 상수 , 함수 , 모듈 , 특히 클래스 및 객체 지향 프로그래밍 에 익숙해야 합니다 .

코드 받기: Python 이름에 단일 및 이중 밑줄을 사용하는 방법을 보여주는 무료 샘플 코드를 다운로드하려면 여기를 클릭하십시오 .

Python의 공용 인터페이스 및 명명 규칙 Python 프로그래머로서 여러분은 공개 인터페이스 나 API(애플리케이션 프로그래밍 인터페이스)를 사용하여 작업하는 경우가 많습니다 . API는 프로그램의 다른 부분이나 다른 프로그램에 서비스를 제공하는 일종의 프로그래밍 인터페이스입니다.

예를 들어 Python 표준 라이브러리에는 특정 서비스를 제공하는 많은 모듈과 패키지가 있습니다. 이러한 모듈과 패키지를 사용하려면 클래스, 함수, 변수, 상수, 모듈과 같은 공용 구성 요소 에 액세스해야 합니다 . 이러한 개체는 모두 모듈이나 패키지의 공개 인터페이스의 일부입니다. 코드에서 직접 사용할 수 있습니다.

그러나 이러한 패키지와 모듈 중 다수는 직접 액세스용이 아닌 개체를 정의합니다. 이러한 개체는 특정 패키지 또는 모듈의 내부 용도로만 사용됩니다. 이는 공개 인터페이스의 일부가 아닙니다.

객체 지향 프로그래밍 의 맥락에서 C++ 및 Java 와 같은 언어에는 공개 및 비공개 메소드 와 속성 이라는 개념이 있습니다 . 이러한 언어에서는 다음과 같은 유형의 클래스 멤버를 사용할 수 있습니다.

Public : 자신의 코드나 클라이언트 코드에서 사용할 수 있습니다. Private : 정의 클래스와 해당 하위 클래스 내부에서만 사용할 수 있습니다. 이러한 언어에는 해당 클래스의 공개 및 비공개 멤버를 정의하는 특정 키워드와 구문이 있습니다. 멤버를 비공개로 선언하면 언어로 인해 액세스가 제한되므로 클래스 외부에서 사용할 수 없습니다. 따라서 비공개 멤버는 클래스의 공개 인터페이스의 일부가 아니며 액세스할 방법이 없습니다.

대조적으로, Python에는 공개 및 비공개 멤버라는 개념이 없습니다. 전용 키워드 나 이를 정의하기 위한 구문이 없습니다 . 따라서 언제든지 Python 클래스의 멤버에 액세스할 수 있습니다.

Python에 객체가 공개 인터페이스의 일부인 시기를 정의 하는 특정 구문이 없다면 사용자에게 주어진 클래스, 메서드, 함수, 변수, 상수 또는 심지어 사용할 수 없는 것을 어떻게 알릴 수 있습니까? 코드에 모듈이 있나요?

이 질문에 접근하기 위해 Python 커뮤니티에는 잘 확립된 명명 규칙이 있습니다 . 다른 개발자가 외부 코드에서 변수, 상수, 함수, 메서드 및 모듈을 직접 사용해야 하는지 여부를 명시적으로 나타내려면 이러한 명명 규칙을 준수해야 합니다.

명명 규칙은 객체에 대한 액세스를 제한하지 않습니다. 이는 귀하의 코드를 사용하는 다른 개발자에게 보내는 경고일 뿐입니다. 이 때문에 Python은 공개 및 비공개라는 용어를 사용하지 않습니다. 대신 public 및 non-public 이라는 용어를 사용합니다 .

Python에서는 이름이 대문자나 소문자로 시작하는 경우 해당 이름을 공개로 간주해야 하며 따라서 코드 API의 일부로 간주해야 합니다. 반대로 이름이 밑줄 문자( _)로 시작하는 경우 해당 이름은 비공개로 간주해야 합니다. 즉, 해당 이름은 코드 API의 일부가 아니라는 의미입니다.

Python 커뮤니티에서는 _다른 명명 규칙의 일부로 밑줄 문자( )를 사용합니다. 다음은 이름에 이 문자를 사용하는 것에 대해 PEP 8에서 말하는 내용을 요약한 것입니다 .

협약예의미
단일 선행 밑줄 _variable 이름이 내부 용도로만 사용됨을 나타냅니다.
단일 후행 밑줄 class_ Python 키워드 및 내장 이름과의 이름 충돌 방지
이중 선행 밑줄 __attribute Python 클래스의 컨텍스트에서 이름 맹글링을 트리거합니다.
이중 선행 및 후행 밑줄 __name__ Python이 제공하는 특별한 속성과 메서드를 나타냅니다.
단일 밑줄 _ 임시 또는 일회용 변수를 나타냅니다.

이러한 규칙 중 두 가지만 특정 Python 동작을 적용합니다. 이중 선행 밑줄을 사용하면 Python 클래스에서 이름 변경이 발생합니다. 이름 변경 섹션에서 이 동작에 대해 자세히 알아볼 것입니다 .

또한 Python 데이터 모델 에 나열된 이중 선행 및 후행 밑줄이 있는 이름은 특정 컨텍스트에서 내부 동작을 트리거합니다. 또한 Python의 던더 이름 섹션에서 이 주제에 대해 자세히 알아볼 것입니다 .

참고: Python은 단일 밑줄( )을 특별하게 처리 하지만 ... 문 _내에서만 사용 됩니다 .

Python 이름의 단일 선행 밑줄

Python에서 공개 및 비공개 이름 만들기

공개 이름은 코드의 공개 인터페이스 또는 API를 정의합니다. 이는 코드 사용자가 코드의 다양한 기능에 액세스하는 데 사용하는 이름입니다. 이러한 이름은 설명적이고 직관적이며 시간이 지나도 안정적이어야 합니다.

In [ ]:
public = "This is a public name."
public

이 시나리오에서 stable이란 이름이 코드 공개 인터페이스의 일부가 되면 해당 이름이 장기간 동일하게 유지되어야 함을 의미합니다. 그렇지 않으면 API에 변경 사항을 도입할 때 발생할 수 있는 사용자 코드가 손상될 위험이 있습니다.

코드의 공개 인터페이스를 디자인할 때 공개 이름을 신중하게 선택해야 합니다. 코드의 모든 객체가 공개되어서는 안 됩니다. 클라이언트 코드에서 사용하면 안 되는 개체가 있고 해당 개체에 공개 이름을 지정하면 코드를 잘못 사용할 위험이 있습니다.

이와 대조적으로 내부 기능을 지원하기 위해 비공개 이름을 만듭니다. 이러한 이름은 API가 아닌 코드 내부 구현의 일부입니다. 따라서 사용자는 코드에 비공개 이름을 사용해서는 안 됩니다. 이러한 이름은 시간이 지남에 따라 변경되거나 향후 코드 버전에서 사라질 수도 있기 때문입니다.

비공개 이름의 예는 다음과 같습니다.

In [ ]:
_non_public = "This is a non-public name."
_non_public

Python 개발자는 객체 이름에 단일 선행 밑줄을 사용하여 객체가 비공개인 경우 이를 알려줍니다.

일반적으로 변수, 클래스, 메서드, 함수 또는 모듈이 포함된 모듈, 클래스 또는 패키지 내에서 내부적으로 사용되도록 지정해야 하는 경우에만 단일 선행 밑줄을 사용해야 합니다. 다시 말하지만 이것은 단지 잘 정립된 명명 규칙일 뿐입니다. Python이 시행하는 엄격한 규칙은 아닙니다. 접근할 수 없는 범위 에 있지 않는 한 비공개 이름에 언제든지 액세스할 수 있습니다 .

이 명명 규칙을 따르고 존중하는 것은 Python 코드를 작성하고 읽을 때 고려해야 하는 모범 사례입니다.

일반적으로 코드가 발전하면서 변경될 가능성이 있는 개체는 비공개로 유지되어야 합니다. 따라서 의심스러운 경우에는 개체에 비공개 이름을 지정하세요. 나중에 지정된 비공개 개체가 코드 API의 일부가 되어야 한다고 결정한 경우 선행 밑줄을 제거할 수 있습니다. 이렇게 하면 API를 안정화하고 사용자 코드 손상을 방지할 수 있습니다.

다른 사람의 코드를 사용하는 경우 개체 이름에 밑줄이 있으면 코드에서 직접 사용하지 않도록 힌트를 얻을 수 있습니다.

Python에서 공개 이름과 비공개 이름 사용

Python 코드를 작성하는 동안 다양한 상황에서 공개 이름과 비공개 이름을 사용할 수 있습니다. 공개 이름은 코드의 공개 인터페이스의 일부입니다. 따라서 이러한 이름은 코드 사용자에게 매우 중요합니다. 설명적이고 기억하기 쉬운 공개 이름을 선택해야 합니다.

대조적으로, 비공개 이름은 대부분 내부용으로 사용됩니다. 이들은 다음 작업 중 일부에 도움을 줄 수 있습니다.

  • 코드의 잘못된 사용 방지 : 코드의 내부 부분을 비공개 이름으로 표시하면 사용자에게 코드의 올바른 사용을 안내할 수 있습니다.
  • 코드 가독성 향상 : 비공개 이름을 적절하게 사용하면 코드를 읽는 다른 사람들이 해당 이름이 내부 전용이라는 것을 즉시 알 수 있으므로 코드 가독성이 향상됩니다.
  • 이름 충돌 방지 : 비공개 이름을 사용하면 패키지, 모듈 및 클래스 간의 이름 충돌을 방지하는 데 도움이 됩니다.

또한 Python의 공개 이름과 비공개 이름 사이에는 몇 가지 다른 차이점도 있습니다. 아마도 문서가 중요한 것입니다. 모든 공개 함수, 메소드, 클래스 및 객체를 문서화해야 합니다. 반면, 비공개 항목은 문서화할 필요가 없습니다.

마지막으로, 코드 편집기, IDE, 코드 린터, REPL 앱과 같은 많은 Python 도구는 공개 이름과 비공개 이름을 구별하기 위해 선도적인 밑줄 명명 규칙을 사용합니다. 코드의 공개 인터페이스에 대한 정보를 화면에 표시할 때 이러한 구별을 사용합니다.

모듈 및 패키지의 공개 및 비공개 이름

Python 모듈은 공개 이름과 비공개 이름을 결정해야 하는 장소 중 하나일 수 있습니다. 모듈 수준에서는 다음 개체 중 일부를 가질 수 있습니다.

  • 상수
  • 변수
  • 기능
  • 클래스

사용자가 모듈 API의 일부로 이러한 객체에 액세스하도록 허용해야 할 수도 있습니다. 그러나 어떤 경우에는 모듈 수준 개체 중 일부가 API의 일부가 아니라는 점을 전달해야 할 수도 있습니다.

모듈 수준 비공개 개체의 일반적인 예는 다음과 같습니다.

  • 내부 변수 및 상수
  • 도우미 함수 및 클래스

다음 섹션에서는 이러한 유형의 개체에 대해 알아봅니다. 비공개 모듈에 대해서도 알아봅니다.

내부 변수 및 상수

모듈에서 전역 변수를 내보내는 것은 좋은 생각이 아닙니다. 전역 변수는 전역 설정, 유틸리티 스크립트, 데이터 캐싱 등 몇 가지 사용 사례에서 유용할 수 있지만 몇 가지 단점이 있습니다. 예를 들어 전역 변수는 다음을 수행할 수 있습니다.

  • 코드 어디에서나 변수를 변경할 수 있으므로 변수 변경 사항을 추적 할 수 없습니다.
  • 전역 변수를 변경하면 코드의 다른 부분 동작에 영향을 미칠 수 있으므로 코드 의 재사용성을 줄입니다.
  • 함수의 동작과 결과가 전역 변수의 현재 값에 따라 달라지므로 코드를 테스트하고 디버그하기 어렵게 만듭니다.
  • 전역 변수에 의존하는 함수는 해당 변수와 밀접하게 결합되므로 코드의 재사용성에 영향을 미칩니다.
  • 코드의 다른 부분에서 실수로 전역 이름을 재사용하여 예상치 못한 결과가 발생할 수 있으므로 이름 지정 충돌이 발생합니다.
  • 전역 변수가 코드의 여러 부분 간에 숨겨진 종속성을 도입하므로 캡슐화가 중단됩니다.
  • 코드의 한 부분을 변경하면 다른 부분에 영향을 줄 수 있으므로 코드를 리팩터링하기 어렵게 만듭니다.

따라서 대부분의 경우 전역 변수를 비공개로 표시하는 것이 좋습니다.

In [ ]:
# count.py

_count = 0

def increment():
    global _count
    _count += 1

def decrement():
    global _count
    _count -= 1

def get_count():
    return _count

이 모듈에서는 모듈 수준 또는 전역 변수를 사용하여 카운터를 유지합니다. 모듈에는 개수를 늘리거나 줄이는 공개 기능이 있습니다. 또한 카운트 상태를 검색하는 기능도 있습니다. 이들 모두는 모듈 공개 인터페이스의 일부이므로 사용자는 코드에서 직접 사용할 수 있습니다.

그러나 _count변수는 이름 앞에 밑줄이 있기 때문에 비공개입니다. 이 세부 정보는 코드 사용자에게 _count코드에서 직접 사용해서는 안 된다는 점을 알려줍니다. 왜?

_count를 직접 사용하지 않음으로써 사용자는 계산 과정에서 잘못된 상태를 피할 수 있습니다. 따라서 이 모듈을 일관되게 사용하려면 사용자는 mutator 함수 increment()와 decrement()와만 현재의 카운터를 변경할 수 있습니다. 사용자가 카운트에 액세스해야 하는 경우 get_count()를 사용해야 합니다.

참고: 위의 예는 설명 목적으로만 사용되었습니다. Python에는 카운터를 작성하는 더 좋은 방법이 몇 가지 있습니다.

객체를 비공개로 만들고 싶은 또 다른 상황은 포함 모듈의 내부 작업에만 관련된 상수가 있는 경우입니다. 다음 예를 고려하십시오.

In [ ]:
# shapes.py

_PI = 3.14

class Circle:
    def __init__(self, radius):
        self.radius = radius

    def calculate_area(self):
        return round(_PI * self.radius**2, 2)

이 코드에서는 _PI이름 앞에 밑줄을 사용하여 비공개 상수인 을 정의했습니다. 선행 밑줄은 다른 개발자에게 이 상수가 shapes.py 모듈 내부에서만 사용된다는 정중한 메시지 역할을 합니다.

이 샘플 모듈에서 공용 개체는 Circle이름에 선행 밑줄이 없는 클래스입니다.

도우미 기능

도우미 함수는 비공개 이름을 사용할 수 있는 또 다른 좋은 예입니다. 도우미 함수의 기본 개념은 코드 재사용이며 대부분의 경우 내부 용도로만 사용됩니다. 모듈 API의 일부가 되어서는 안 됩니다.

예를 들어, 이전 섹션의 shapes.py 파일로 돌아가서 클래스 반경이 0보다 큰지 확인하기 위해 Circle 클래스 반경의 유효성을 검사해야 한다고 가정해 보겠습니다 . 이 경우 유효성 검사를 위한 도우미 함수를 사용할 수 있습니다. 그런 다음 다른 모양에서 도우미 함수를 재사용할 수 있습니다.

In [ ]:
# shapes.py

_PI = 3.14

class Circle:
    def __init__(self, radius):
        self.radius = _validate(radius)

    def calculate_area(self):
        return round(_PI * self.radius**2, 2)

class Square:
    def __init__(self, side):
        self.side = _validate(side)

    def calculate_area(self):
        return round(self.side**2, 2)

def _validate(value):
        if not isinstance(value, int | float) or value <= 0:
            raise ValueError("positive number expected")
        return value

shapes.py의 새 버전에서는 모듈 끝에 _validate() 도우미 함수를 추가합니다 . 이 함수는 값을 인수로 사용하고 그것이 양수인지 확인합니다. 그렇지 않은 경우에는 ValueError 예외가 발생합니다. 그렇지 않으면 동일한 입력 인수를 얻게 됩니다.

Circle및 Square 클래스에서 이 도우미 함수를 어떻게 재사용하는지 확인하세요. 그러나 이 함수를 모듈 API의 일부로 만들 필요는 없으므로 이름 앞에 밑줄을 사용하여 비공개 함수임을 나타냅니다.

비공개 모듈

모듈 이름 앞에 밑줄을 사용하는 것도 가능하다는 것을 알아야 합니다. 예를 들어, CPython 소스 코드 에서 많은 모듈 이름은 앞에 밑줄로 시작하여 해당 모듈이 코드 일부의 내부 구현을 제공한다는 것을 나타냅니다.

이러한 모듈은 언어의 공개 API의 일부가 아니기 때문에 표준 라이브러리나 내장 공간에서 직접 액세스할 수 없다는 점을 곧 알게 될 것입니다.

자신의 Python 프로젝트에는 내부용으로만 코드를 제공하는 모듈이 있을 수 있습니다. 이러한 경우 이름 앞에 밑줄을 사용하여 다른 개발자에게 코드에서 직접 이러한 모듈을 사용해서는 안 된다는 점을 알릴 수 있습니다.

와일드카드 가져오기 및 비공개 이름

때로는 모듈에 정의된 모든 이름을 현재 네임스페이스로 가져오기 위해 양식의 와일드카드를 사용하는 Python 라이브러리 import를 찾을 수 있습니다. GUI 개발을 위한 Tkinter from module import * 라이브러리 는 이러한 관행의 좋은 예입니다. 이러한 유형의 가져오기는 Python의 스타일 가이드인 PEP 8 에서 사용을 권장하지 않기 때문에 특별히 일반적이지 않습니다.

와일드카드 가져오기( from import *)는 네임스페이스에 어떤 이름이 있는지 불분명하게 만들어 판독기와 많은 자동화 도구 모두를 혼란스럽게 하기 때문에 피해야 합니다. ( 원천 )

그러나 와일드카드 가져오기가 유용하고 빠른 경우도 있습니다. 와일드카드 가져오기를 올바르게 사용하려면 비공개 이름을 가져오지 않는다는 점을 알아야 합니다. 이 Python 동작을 확인하려면 shapes.py 파일이 있는 디렉터리에서 REPL 세션을 엽니다 . 그런 다음 다음 코드를 실행합니다.

In [ ]:
from shapes import *

dir()

이 코드 조각에서는 와일드카드 가져오기가 Circle 및 Square 클래스만 가져오는 것을 볼 수 있습니다. 상수 _PI와 _validate() 도우미 함수가 현재 네임스페이스에 없습니다 .

Python은 위의 동작을 시행합니다. 그러나 이 동작은 와일드카드 가져오기에만 적용됩니다. 다른 가져오기 명세서 양식을 사용하여 비공개 이름에 계속 액세스할 수 있습니다.

In [ ]:
from shapes import _PI

_PI
In [ ]:
import shapes

shapes._PI

와일드카드 가져오기 이외의 가져오기 양식을 사용하면 비공개 이름을 현재 네임스페이스로 가져올 수 있습니다. 이 예에서는 비공개 개체인 경우에도 shapes.py 에서 _PI 상수를 가져옵니다. shapes 모듈에서 점 표기법을 사용하여 _PI에 액세스할 수도 있습니다 . 이와 같은 작업을 수행하면 비공개 이름과 관련하여 확립된 명명 규칙의 의도를 우회한다는 점을 명심하십시오.

비공개 member 포함된 class

신, 공개 이름과 비공개 이름을 구별하기 위해 확립된 명명 규칙이 있습니다. 그러나 해당 규칙을 준수하는 것은 개발자의 몫입니다. 모든 Python 이름은 다른 범위에 있지 않는 한 어떤 방식으로든 액세스할 수 있습니다.

공개 이름과 비공개 이름의 구별은 객체 지향 프로그래밍의 맥락에서 더욱 중요합니다. PEP 8이 클래스의 속성을 참조할 때 이러한 용어를 정의하는 방법은 다음과 같습니다.

공개 속성은 이전 버전과 호환되지 않는 변경을 방지하겠다는 약속과 함께 클래스의 관련 없는 클라이언트가 사용할 것으로 예상하는 속성입니다. 비공개 속성은 제3자가 사용하도록 의도되지 않은 속성입니다. 비공개 속성이 변경되거나 제거되지 않을 것이라는 보장은 없습니다. ( 원천 )

다시 말하지만, 멤버 라고도 하는 공용 클래스 특성 및 메서드는 클래스의 공용 인터페이스의 일부이지만, 공용이 아닌 멤버는 클래스의 일부가 아닙니다. 정의 클래스 외부에서 비공개 멤버를 사용하지 않는 것이 가장 좋습니다. 비공개 멤버는 비공개 멤버이므로 이를 존중해야 합니다.

대부분의 경우 비공개 멤버는 특정 클래스의 내부 구현을 지원하기 위해서만 존재하며 언제든지 사라질 수 있으므로 사용자는 이에 의존해서는 안 됩니다.

비공개 속성

Python 클래스에서 비공개 속성의 여러 사용 사례를 찾을 수 있습니다. 이러한 유형의 속성은 여러 가지 다른 용도로 사용될 수 있습니다. 그 중 일부는 다음과 같습니다.

  • 캡슐화 촉진 : 비공개 속성을 사용하여 내부 구현 세부 정보를 숨겨 캡슐화를 시행할 수 있습니다.
  • 캐싱 및 메모 구현 : 비공개 속성을 사용하여 비용이 많이 드는 계산 결과를 캐시 하거나 메모할 수 있습니다.
  • 내부 상태 보호 : 비공개 특성을 사용하여 클래스의 공개 인터페이스의 일부가 아닌 내부 상태 정보를 저장할 수 있습니다.

클래스를 작성할 때 속성이 공개인지 비공개인지 결정하기 어려울 때가 있습니다. 이 결정은 사용자가 클래스를 어떻게 사용하기를 원하는지에 따라 달라집니다. 대부분의 경우 클래스의 안전한 사용을 촉진하려면 속성을 비공개로 설정해야 합니다.

이 아이디어에 따라 모든 속성을 비공개로 시작하고 실제 사용 사례가 나타날 경우에만 공개하는 것이 좋은 접근 방식입니다.

참고: 비공개 속성에 액세스하고 수정하는 것은 데이터 캡슐화를 직접적으로 위반합니다 . 이는 정의 클래스 외부에서 비공개 멤버를 사용하지 않는 또 다른 이유입니다.

Python에서는 클래스의 공개 인터페이스의 일부로 속성을 노출하는 것이 일반적인 관행입니다. 그 이유는 주어진 속성 위에 기능적 동작을 추가해야 하는 경우 언제든지 속성을 속성 으로 전환할 수 있기 때문입니다.

설명을 위해 Point 클래스를 정의해야 한다고 가정해 보겠습니 . 클래스에는 데카르트 좌표를 나타내는 두 가지 속성이 있습니다.

In [ ]:
# point.py

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

이 클래스에는 점의 좌표를 나타내는 두 개의 공개 속성 .x 및 .y가 있습니다. 평소와 같이 점 표기법을 사용하여 이러한 속성에 액세스하고 변경할 수 있습니다.

In [ ]:
from point import Point

point = Point(12, 5)

# Access the coordinates
point.x
In [ ]:
point.y
In [ ]:
# Update a coordinate
point.x = 24
point.x
In [ ]:
# Assign an invalid data type
point.y = "10"
point.y

이 짧은 예에서 결론을 내릴 수 있듯이 점 표기법을 사용하여 속성에 직접 액세스하고 업데이트할 수 있습니다. 마지막 예에서는 Point 클래스가 좌표에 할당한 값의 유효성을 검사하지 않으며 이는 올바른 사용 방법이 아닐 수 있다는 점에 유의해야 합니다.

데이터 유형 불일치를 해결하려면 적절한 유효성 검사 논리를 구현할 수 있도록 .x 및 .y 속성 위에 함수 동작을 추가할 수 있습니다. 일반 속성으로는 그렇게 할 수 없습니다. 메소드나 함수가 필요합니다.

속성을 속성으로 전환하면 클래스의 공용 인터페이스를 수정하지 않고도 이 문제를 해결할 수 있습니다.

In [ ]:
# point.py

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = _validate(value)

    @property
    def y(self):
        return self._y

    @y.setter
    def y(self, value):
        self._y = _validate(value)

def _validate(value):
    if not isinstance(value, int | float):
        raise ValueError("number expected")
    return value

Point의 새 버전에서는 많은 일이 일어나고 있습니다. 첫 번째 눈에 띄는 변화는 속성 이름을 딴 메서드 내부의 비공개 속성에 좌표를 저장했다는 것입니다. @property 데코레이터를 사용하여 getter 메서드를 정의하고 @attribute_name.setter 데코레이터를 사용하여 setter 메서드를 정의하는 속성으로 두 특성을 모두 구현합니다 .

setter 메서드에서는 _validate()도우미 함수를 사용하여 입력 값이 유효한 숫자인지 확인합니다. 클래스 API의 일부가 아닌 해당 비공개 속성에 실제 값을 저장하는 방법에 유의하세요. 내부의 공개 속성을 사용하면 __init__() 인스턴스화 시에도 유효성 검사가 수행됩니다.

Python의 속성을 사용하면 함수와 유사한 동작으로 속성을 생성할 수 있습니다. 그러나 속성을 메서드로 호출할 필요는 없습니다. 일반 속성으로 계속 액세스할 수 있습니다.

In [ ]:
from point import Point

point = Point(12, 5)

point.x
In [ ]:
point.y
In [ ]:
point.x = 24
point.x
In [ ]:
from point import Point

point = Point(12, 5)

point.y = "10"
point.y  # 출처에서는 ValueError이 발생한다고 하였는데 정상적으로 실행됨

이 코드 조각에서는 이전과 마찬가지로 point 인스턴스를 사용합니다. API는 변경되지 않았습니다. 그러나 좌표 중 하나에 잘못된 값을 할당하려고 하면 ValueError가 나타납니다. 이는 새 값을 할당할 때마다 속성의 setter 메서드가 실행되기 때문에 발생합니다. 따라서 _validate() 함수는 .x 또는 .y 값을 업데이트하려고 할 때마다 실행됩니다.

비공개 속성 ._x및 _y을 관리하기 위해 속성을 정의했더라도 해당 속성에 직접 액세스할 수 있다는 점에 유의하는 것이 중요합니다.(출처와 달리 에러가 났습니다.)

In [ ]:
point._y
In [ ]:
point._y

선행 밑줄은 단지 명명 규칙일 뿐이라는 점을 기억하십시오. Python은 이러한 유형의 속성에 대한 액세스를 제한하지 않습니다. Python 개발자는 규칙을 준수해야 하며 외부에서 비공개 속성에 액세스해서는 안 됩니다. 왜?

이 특정 예에서 유효성 검사를 우회하기 위해 _x 혹은 _y에 새 값을 할당하면, 잘못된 동작이 발생하거나 코드의 다른 부분이 손상될 수도 있습니다.

In [ ]:
point._y = "10"
point._y
In [ ]:
point.y

이제 .y 좌표에 잘못된 값이 어떻게 포함되어 있는지 확인하세요 . 이제 숫자 대신 문자열이 포함됩니다. 이는 규칙을 위반하고 기본 비공개 속성을 변경한 직접적인 결과입니다.

비공개 방법

Python 클래스에서 비공개 메서드를 사용할 수도 있습니다. 이러한 유형의 메서드는 클래스의 내부 작업에 필수적일 수 있습니다. 그러나 클래스 인터페이스의 일부는 아닙니다. 비공개 메서드에 대한 많은 사용 사례를 찾을 수 있습니다. 그 중 일부는 다음과 같습니다.

  • 도우미 메서드 : 비공개 메서드는 공용 메서드를 지원하는 반복 논리를 캡슐화하는 데 도움이 됩니다. 또한 이를 사용하여 긴 메서드나 복잡한 논리가 포함된 메서드를 각각 단일 책임이 있는 여러 도우미 메서드로 분할할 수 있습니다 .
  • 데이터 유효성 검사 및 무결성 : 비공개 메서드를 사용하면 클래스 내 데이터의 유효성을 검사할 수 있습니다. 이를 사용하면 유효성 검사 논리를 외부 코드에 노출하지 않고도 일관성을 보장하고 데이터 무결성을 유지할 수 있습니다.
  • 구현 세부 정보 : 비공개 메서드를 사용하면 클래스의 내부 구현 세부 정보를 숨길 수 있습니다. 이를 사용하여 복잡한 알고리즘과 데이터 변환을 캡슐화할 수 있습니다.
  • 코드 구성 : 비공개 방법을 사용하면 크고 복잡한 클래스를 구성하는 데 도움이 됩니다. 이를 사용하여 코드 가독성과 유지 관리성을 향상시킬 수 있습니다.

이러한 사용 사례 중 하나를 설명하기 위해 쉼표나 탭 문자를 사용하여 값을 구분하는 CSV 파일 로 작업한다고 가정해 보겠습니다 . 쉼표를 사용하는 파일을 처리하는 방법과 탭을 사용하는 파일을 처리하는 또 다른 방법을 제공하는 클래스를 작성해야 합니다.

이 클래스의 가능한 구현은 다음과 같습니다.

In [ ]:
# csv_data.py

import csv

class CSVFileManager:
    def __init__(self, file_path):
        self.file_path = file_path

    def read_csv(self):
        return self._read(delimiter=",")

    def read_tsv(self):
        return self._read(delimiter="\t")

    def _read(self, delimiter):
        with open(self.file_path, mode="r") as file:
            return [row for row in csv.reader(file, delimiter=delimiter)]

이 클래스에는 공개 인터페이스의 일부로 .read_csv()와 .read_tsv() 두 가지 메서드가 있습니다. ._read() 도우미 메서드에는 두 공개 메서드 모두에 대한 기본 코드가 있습니다. 이 도우미 메서드를 사용하면 .read_csv()및 .read_tsv()에서 논리가 반복되는 것을 방지할 수 있습니다 .