[TIL] Python - module, package, set, OOP

한울·2026년 1월 2일

What I Learned

모듈, 패키지, 라이브러리

  • 모듈 : 파이선 파일 하나
  • 패키지 : 모듈들을 담은 폴더
프로젝트
 └─ 패키지
     └─ 모듈
         └─ 함수 / 클래스 / 변수

if __name__ = “__main__”

Python 공식 문서

  • __name__은 파이썬 모듈이 직접 실행되었는지(import가 아닌지)를 판별하기 위해 인터프리터가 자동으로 부여하는 특수 변수이다.
  • __main__은 Python의 최상위 코드 실행 환경이다. (Top-level code environment)
  • if __name__ = “__main__”은 스크립트가 최상위 코드 실행 환경에서 실행되었는지 확인한다.
  • import해서 쓰는 모듈로 쓸 것인지, 직접 실행하는 프로그램으로 쓸 것인지 구분하기 위한 장치다.
  • mymath라는 모듈을 만들었다고 가정하면, mymath.py에서 __name____main__이다.
    # mymath.py
    print(__name__) # __main__
  • mymath를 import해서 쓰면, __name__mymath가 된다.
    import mymath

	print(mymath.__name__) # mymath

name mangling

  • Python에서 변수 이름 앞에 underscore를 1개 작성하면, 사용하지 말라는 신호이다. (그러나 접근을 막지는 않는다.)
  • underscore를 2개 작성하면 name mangling이 적용되어 클래스 외부 및 하위 클래스에서 이름 충돌을 방지하지만, 접근을 완전히 막지는 않는다.
class UserAccount:
    def __init__(self, username, password):
        self.username = username
        self.__password = password  

user1 = UserAccount("alice", "securepass")
user1.__password = "hacked"

print(user1.__dict__)
  • print(user1.__dict__)의 결과를 확인하면 다음과 같다.
{'username': 'alice', '_UserAccount__password': 'securepass', '__password': 'hacked'}
  • _UserAccount__password는 클래스 내부에서 __password로 정의된 변수에 name mangling이 적용된 실제 속성이며, 값은 securepass이다.
  • __password는 인스턴스에 새로 추가된 속성으로, 기존의 변수와는 전혀 다른 변수이다.

@property

  • name mangling만 사용했을 경우, 숨겨야 할 변수에 접근이 가능하다.
print(user1._UserAccount__password) # securepass
  • Python에서 캡슐화는 private 키워드로 속성을 숨기는 것이 아니라 @property를 사용해 속성 접근을 메서드로 제어하는 방식으로 구현한다.
class UserAccount:
    def __init__(self, username, password):
        self._password = password  # 내부 저장용
        self.username = username

    @property
    def password(self):
        raise AttributeError("password는 직접 접근할 수 없습니다.")

    def check_password(self, pw):
        return self._password == pw

user2 = UserAccount("George", "mypassword")
try:
    print(user2.password)  # AttributeError 발생
except AttributeError as e:
    print(f"에러: {e}")
  • @property는 메서드를 속성처럼 접근하게 만드는 getter이다.
class Student:
    def __init__(self, name, grade):
        self.name = name
        self._grade = None      # 내부 상태 명시
        self.grade = grade      # 검증 로직은 setter로

    @property
    def grade(self):
        return self._grade
    
    @grade.setter
    def grade(self, value):
        if not (1 <= value <= 12):
            raise ValueError("학년은 1에서 12 사이여야 합니다.")
        self._grade = value

student = Student("Alice", 5)
print(f"{student.name}의 학년: {student.grade}") # getter 사용
student.grade = 10 # setter 사용
print(f"{student.name}의 학년 변경 후: {student.grade}") # getter 사용
  • student.grade는 속성에 접근하는 것처럼 보이지만, Student 클래스 내부의 grade getter 메서드를 호출한다.
  • student.grade = 10는 단순한 속성 대입이 아니라, @grade.setter로 정의된 setter 메서드가 호출되어 값 검증 로직을 거친 뒤 내부 변수(_grade)에 값이 저장된다.
  • 단, @property는 인터페이스 접근을 통제할 뿐 내부 속성 접근까지 막지는 않는다.

느낀 점

Java로 먼저 OOP를 배운 나로써는 파이썬의 "private" 변수의 동작 방식이 처음에 크게 와닿지 않았다. Java에서는 접근 제어자를 통해 접근 범위가 문법적으로 엄격히 제한되는데, 파이썬에서는 undescore를 사용한 관례 중심의 접근 제어를 선택하고 있다. "We are all consenting adults here"이라는 Python의 설계 철학을 잘 보여주는 사례이지 않을까 싶다.

profile
데이터 공부

0개의 댓글