Skip to content

2.11. 내용정리: 11일차

흔한 찐따 edited this page Mar 22, 2022 · 3 revisions

패키지 (Packages)

  • 파이썬에서 모듈은 하나의 .py 파일이다.
  • 패키지(Packages) 란, 접근 연산자 도트( . )를 사용하여 파이썬 모듈을 계층적(디렉터리 구조)으로 관리할 수 있도록 해준다.
  • 예를 들어, 모듈 이름이 A.B 인 경우에 A 는 패키지 이름이 되고, B 는 패키지 A 의 모듈 B 가 된다.

패키지를 사용하는 이유

  • 간단한 파이썬 프로그램이 아니라면 패키지 구조로 파이썬 프로그램을 만드는 것이 공동 작업이나 유지 보수 등 여러 면에서 유리하다.
  • 또한, 패키지 구조로 모듈을 만들면 다른 모듈과 이름이 겹치더라도 더 안전하게 사용할 수 있다.

패키지 만들기

패키지를 만드는 방법은 다음과 같다.

  1. 자신이 원하는 패키지명으로 디렉터리를 생성한다.
  2. __init__.py 파일을 생성한다.
  3. 패키지 안에 또다른 패키지를 생성하고 싶다면, 자신이 원하는 패키지명으로 서브(하위) 디렉터리를 생성한다.
  4. 생성했던 서브 디렉터리 안에 __init__.py 파일을 생성한다.
  5. 자신이 만들고자 하는 모듈을 만든다.

예시

예를 들어, 다음과 같이 my_package 라는 모듈을 만든다고 가정해보자.

  1. my_package 라는 디렉터리를 생성한다.
  2. my_package 라는 패키지 안에 A , B 라는 서브 디렉터리를 생성한다.
  3. 패키지 A 안에 test1test2 라는 모듈을 생성한다.
  4. 패키지 B 안에 test3test4 라는 모듈을 생성한다.

위의 내용을 구조로 나타내면 다음과 같다.

my_package/
    __init__.py
    A/
        __init__.py
        test1.py
        test2.py
    B/
        __init__.py
        test3.py
        test4.py

__init__.py 의 용도

  • __init__.py 파일은 해당 디렉터리가 패키지의 일부임을 알려주는 역할을 한다.
  • 만약 위에서 든 예시의 경우, 패키지 AB 패키지에 포함된 디렉터리에 __init__.py 파일이 없다면 패키지로 인식되지 않는다.
  • 즉, __init__.py 라는 파일은 파이썬 패키지를 인식시켜주는 파일이다.
  • 주로 패키지가 import 될 때 초기화하는 작업을 하는 용도로 사용된다.

관계(relative) 패키지

만약 디렉터리 Btest3.py 모듈에서 디렉터리 Atest1.py 모듈을 사용하고 싶다면 다음과 같이 test3.py 를 수정하면 가능하다.

# test3.py

from my_package.A import test1

위 예제처럼 from my_package.A import test1 을 입력해 전체 경로를 사용하여 import 할 수도 있지만 다음과 같이 relative 하게 import 하는 것도 가능하다.

# test3.py

from ..A import test1

설명

  • from my_package.A import test1from ..A import test1 로 변경되었다.
  • 여기에서 ..test1.py 파일의 상위(부모) 디렉터리를 의미한다.
  • 따라서 test1.py 파일의 상위 디렉터리는 A 이므로 위와 같은 import 가 가능한 것이다.

test1.py 파일의 현재 디렉터리는 A 이고, 상위 디렉터리는 my_package 이다.

relative한 접근자에는 다음과 같은 것이 있다.

  • .. : 상위(부모) 디렉터리
  • . : 현재 디렉터리

몽키 패치 (Monkey Patch)

  • 몽키 패치란, 프로그램이 내부 프로그램을 로컬에서 잠시 다른 기능을 수행하도록 수정하거나 확장하도록 하는 방법이다.
    • 요약하자면, 프로그램을 확장하거나, 로컬 시스템 소프트웨어를 지원하고 수정하는 방법이다.
    • 또한, 오직 실행중인 프로그램의 인스턴스에 영향을 미친다.
  • 이는 로컬이므로, 프로그램 동작 시(즉, 런타임 도중)에만 영향을 주는 방식이다.
  • 다시 말해, 런타임 상에서 함수, 메서드, 속성을 바꾸는 것을 의미한다.
  • 소스 코드가 없는 서드 파티 제품을 사용하는 중 기능을 변경하거나 확장을 위해 사용한다.
  • 런타임 실행중 메모리 상의 오브젝트에 적용된다.

어원

  • 이름의 유래는 원래 게릴라 패치였다고 한다.
  • 게릴라란, 집단에 속하지 않고 개별적인 행위를 하는 사람 또는 단체라는 의미로 그냥 개인 플레이라고 생각하면 된다.
  • 게릴라 패치라는 이름 그대로 특정 기능을 위해 개별적인 행위를 해서 이러한 이름이 붙여졌을 것이다.
  • 게릴라패치가 몽키패치가 된 건 발음의 유사성에 있다.
  • 즉, 게릴라(Guerrilla) -> 고릴라(Gorilla) -> 원숭이(Monkey) 순으로 변화한 것이다.
  • 게릴라 패치에서 발음의 유사한 고릴라패치로 변했는데 고릴라 패치라고 하면 너무 크고 거대한 패치라고 들리는 문제점이 있었다고 한다.
    • 실은 런타임에서 돌아가는 상대적으로 자그마한 변화였는데도 불구하고 말이다.
  • 그래서 이번에는 발음의 유사성보단 종의 '유사성 + 귀여움'으로 인해 원숭이로 바뀌게 되었다고 한다.

예시

다음과 같이 test 라는 모듈이 있고, hello 라는 함수가 정의되어 있다고 가정하자.

# test.py
def hello():
    print('Hello, Python!')

그리고 이 모듈을 import 한 모듈 test2 를 새롭게 생성한다.

# test2.py
import test

그 다음 기존에 모듈 test 에 정의한 함수 hello 를 다시 재정의한다.

#test2.py
import test

def hello():
    print('Hi, Python!')

test.hello 를 재정의한 함수 hello 로 변경해준다.

# test2.py
import test

def hello():
    print('Hi, Python!')

test.hello = hello

즉, 모듈 testimport 한 후에 모듈 test2 도 같이 import 하게 된다면 test2 에서 재정의한 함수 hello 로 변경될 것이다.

import test
import test2

# 'Hi, Python!'이 출력된다.
test.hello()

클래스 역시 재정의하는 것이 가능하다.

# test.py
class MyClass:
    def hello(self):
        print('Hello, Python!')

위의 test 모듈에서 정의한 MyClass 를 새롭게 생성한 모듈 test2 의 클래스 MyClass2 로 변경시킨다.

# test2.py
import test

class MyClass2:
    def hello(self):
        print('Hi, Python!')

test.MyClass = MyClass2

그리고 아래의 예시처럼 모듈 testtest2import 해서 hello 메서드를 호출해본다.

import test
import test2

m = test.MyClass()
m.hello()