Skip to content

Latest commit

 

History

History
197 lines (123 loc) · 8.93 KB

python(10.module&package, 11.class).md

File metadata and controls

197 lines (123 loc) · 8.93 KB

10.모듈과 패키지

모듈

파이썬 파일은 각각 하나의 모듈로 취급된다.

__name__변수

module/lol.py

import game

print('= Turn on game =')
game.play_game()
shop.buy_item()

module/game.py

def play_game():
    print('Play game!')

play_game()

위와 같은 파일이 있다고 하자. lol.py가 실행될 때 game이 import 되는 순간 play_game() 실행되어 버리는 문제가 생겨서 결과적으로 play_game이 두 번 실행되어지게 된다. 이런 문제를 해결하기 위해 단순히 import 되어진 경우에는 실행을 막아야 한다.

각 모듈은 자신의 이름을 가지며, 모듈 이름은 모듈의 전역변수 __name__에서 확인할 수 있다.

파이썬 인터프리터가 실행한 모듈의 경우에는 __main__이라는 이름을 갖게 되는데, 예를 들어 lol.py를 인터프리터로 실행하게 되면 이 때 lol.py의 이름은 인터프리터가 실행한 모듈이기 때문에 __main__ 이고 game.py의 이름은 인터프리터가 실행한 모듈이 아니기 때문에 __main__이 아닌 다른 이름을 갖게 된다. 따라서 game.py의 코드를 다음과 같이 바꿔주면 lol.py를 실행했을때 단순히 import 되어진 경우에는 game.py가 실행되어지지 않는다.

def play_game():
    print('Play game!')

if __name__ == '__main__':
    play_game()

패키지

패키지는 모듈들을 모아 둔 특별한 폴더를 뜻한다. (일반적인 폴더와는 다르다)

폴더를 패키지로 만들면 계층 구조를 가질 수 있으며, 모듈들을 해당 패키지에 모을 수 있는 역할을 한다.

패키지를 만들 때는 패키지로 사용할 폴더에 __init__.py파일을 넣어주면, 해당 폴더는 패키지로 취급된다. (비어있어도 무관하며, python3에서는 없어도 된다.)

shop.pygame.pyfunc패키지에 넣어본다.

├── func
│   ├── __init__.py
│   └── game.py
│  
└── lol.py

패키지는 모듈과 동일하게 import할 수 있으며, 위와 같이 func패키지에 모듈들을 넣은 경우에는

from func import game, shop으로 기존 코드의 변경 없이 패키지에서 모듈을 가져오는 방식을 사용할 수 있다.

또는 단순히 import funcfunc.game, func.shop을 사용하는 방식도 가능하다.

*, __all__

패키지에 포함된 하위 패키지 및 모듈을 불러올 때, *을 사용하면 해당 모듈의 모든 식별자들을 불러온다.

이 때, 각 모듈에서 자신이 import될 때 불러와질 목록을 지정하고자 한다면 모듈 내부에 __all__ 을 정의하면 된다. (*로 import 되어질 때 모든 내용을 import 하고자 한다면 굳이 정의할 필요는 없다)

game.py

__all__ = (
	'play_game'
)

또한, 패키지를 하위의 모든 모듈을 부르기 위해 *을 쓸 때 불러와질 목록은 __init__.py 안에 __all__로 지정하여 주면 된다. ( 모듈이 import 되어질 때와는 다르게 패키지 하위의 모든 모듈을 부르기 위해 *을 쓰는 경우에는 __init__.py에 필수로 모든 모듈을 지정하여 주어야 한다.)

func/__init__.py

__all__ = (
	'game'
)

패키지 자체를 import시에 자동으로 가져오고 싶은 목록이 있다면, 패키지의 __init__.py파일에 해당 항목을 import해주면 된다.


11.클래스(class)

객체지향 프로그래밍

파이썬의 모든것은 객체이며, 객체를 사용할 때는 변수에 해당 객체를 참조(Reference)시켜 사용한다.
객체는 변수와 함수를 가지며, 특별히 객체가 가진 변수와 함수는 각각 속성(attribute)메서드(method) 라고 부른다.

객체는 어떠한 타입, 즉 특정한 클래스의 형태를 가진 인스턴스를 나타낸다.

클래스

클래스 속성

' '

속성 접근 지정자(attribute access modifier)

캡슐화

객체를 구현할 때, 사용자가 반드시 알아야 할 데이터나 메서드를 제외한 부분을 은닉시켜 정해진 방법을 통해서만 객체를 조작할 수 있도록 하는 방식.

속성 이름을 __로 시작하면, 외부에서의 접근을 제한한다. 이 경우를 private 지정자라고 한다.

파이썬은 속성을 실제로 사용하지 못하도록 숨기지는 않고, 네임 맹글링(name mangling)이라는 기법을 사용한다. 파이썬에서는 문법적으로 pirvate데이터에 대한 접근을 막는 법을 제공하지는 않는다. 이는 개발자에게 최대한 제약을 가하지 않겠다는 파이썬의 철학 때문이다.

get/set 속성값과 프로퍼티

파이썬에서는 지원하지 않지만, 어떤 언어들은 외부에서 접근할 수 없는 private객체 속성을 지원한다. 이 경우, 객체에서는 해당 속성을 읽고 쓰기 위해 getter, setter메서드를 사용해야 한다.

파이썬에서는 해당 기능을 프로퍼티(property)를 사용해 간편히 구현한다.
다음과 같은 shop이라는 class가 있다고 가정하여 보자.

class Shop:
	def __init__(self, name):
		self.__name = name

위의 class에서 self.__nameprivate 지정자이다. 이 속성을 읽어 들이기 위해 프로퍼티를 구현해보자.

@property
def name(self):
	return self.__name

# 프로퍼티는 메서드 위에 @property 데코레이터를 붙여야 한다.
# 또한 프로퍼티는 self 이외에 매개변수가 오면 안된다.

위의 name은 메서드처럼 보이지만 속성처럼 작용한다. 따라서 위의 메서드를 호출하기 위해서 name 뒤에 ()를 붙여줄 필요가 없이 인스턴스.name이라고만 입력하면 된다.

위 프로퍼티에 대해 실제로 속성값을 넣을 수 있는 setter를 만들어 보자. setter는 프로퍼티에 해당하는 이름으로 데코레이터를 붙여야하며 함수 이름은 같아야 한다.

@name.setter
def name(self, new_name):
	self.__name = new_name
	print('Set new name ({})'.format(self.__name))

이렇게 만들어진 setter로 private 지정자self.__name을 조작할 수 있다.

정적(스태틱) 메서드

스태틱 메서드는 클래스 내부에 정의된 일반 함수이며, 단지 클래스나 인스턴스를 통해서 접근할 수 있을 뿐 해당 클래스나 인스턴스에 영향을 주는 것은 불가능하다.

스태틱메서드는 @staticmethod데코레이터를 붙여 선언한다.

스태틱메서드는 다양한 방식으로 인스턴스를 생성하는 클래스를 작성할 때 자주 사용된다. __init__()초기화 함수는 하나만 존재할 수 있기 때문에, 다른 생성함수를 정적 메서드로 만들어 사용할 수 있다.

self를 첫 인자로 받던 인스턴스 메서드와는 다르게 self를 인자로 받지 않는다.

클래스 메서드

클래스 메서드는 클래스 속성에 대해 동작하는 메서드이다. 위의 인스턴스 메서드와 달리 호출 주체가 클래스이며, 첫 번째 인자도 클래스이다.
만약 인스턴스가 첫 번째 인자로 주어지더라도 해당 인자의 클래스로 자동으로 바뀌어 전달된다.

클래스메서드는 @classmethod데코레이터를 붙여 선언하며, 첫 번째 인자의 이름은 관용적으로 cls를 사용한다.

클래스 메서드를 사용하면 부모 클래스를 상속받은 자식클래스에서 해당 부모클래스의 클래스 메서드를 사용할 경우, 자기 자신(자식)의 클래스를 사용할 수 있다.
즉, 스태틱 메서드를 상속받은 자식 클래스에서 부모의 스태틱 메서드를 사용하면 자식 클래스임에도 불구하고 부모클래스를 반환하게 되는데, 이와 달리 클래스 메서드를 사용하게 되면 자식 클래스는 자기 자신의 클래스를 반환하게 된다.


상속

메서드 오버라이드

상속받은 클래스에서, 부모 클래스의 메서드와는 다른 동작을 하도록 할 수 있다. 이 경우 부모 클래스의 메서드를 덮어씌워서 사용하도록 하며, 이 방법을 메서드 오버라이드(method override)라고 한다.

부모 클래스의 메서드를 호출 (super)

자식클래스의 메서드에서 부모 클래스에서 사용하는 메서드의 전체를 새로 쓰는것이 아닌, 부모 클래스의 메서드를 호출 후 해당 내용으로 새로운 작업을 해야 할 경우 super()메서드를 사용해서 부모 클래스의 메서드를 직접 호출할 수 있다.

class Restaurant(Shop):
    def __init__(self, name, shop_type, address, rating):
        super().__init__(name, shop_type, address)
        self.rating = rating

위 코드의 경우, super()메서드를 사용해서 부모의 __init__ 메서드를 호출한다.