Git에서 Clone한 프로젝트 사용하기

기존 환경 백업 후 삭제

# 설치된 패키지 버전까지 모두 확인가능
$ pip freeze

# 설치 리스트들을 파일로 내보내기
$  pip freeze > requirements.txt
# shell script
## > 덮어쓰기
## >> 붙여넣기
# requirements.txt도 git으로 관리해야함

# virtualenv 설정한 폴더로 이동
$ cd /your/dir/path
$ rm .python-version
# 삭제 확인
$ pyenv version
3.4.3 (set by /usr/local/var/pyenv/version)

# virtualenv 삭제
$ pyenv uninstall fc-python
pyenv-virtualenv: remove /usr/local/var/pyenv/versions/3.4.3/envs/fc-python? y

# 삭제 확인
$ pip list
You are using pip version 6.0.8, however version 9.0.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
pip (6.0.8)
setuptools (12.0.5)

$ pyenv version
3.4.3 (set by /usr/local/var/pyenv/version)

clone받은 프로젝트의 환경에 맞게 설정

# 가상환경 생성
$ pyenv virtualenv 3.4.3 fcpy
# 가상환경 사용 설정
$ pyenv local fcpy
# 설정 적용 확인
$ pyenv versions

# requirements가 있을 경우 설치
$ pip install -r requirements.txt

# error!
# Command "/usr/local/var/pyenv/versions/3.4.3/envs/fcpy/bin/python -c "import setuptools,

# 에러 해결을 위해 pip 업그레이드
$ pip install --upgrade pip

# error!
# Could not import setuptools which is required to install from a source distribution.

# 에러 해결을 위해 setuptools 설치
$ pip install -U setuptools
$ pip install -r requirements.txt
$ pip list

# 하위 폴더에도 가상환경 설정
# 상위 폴더와는 영향이 없음
$ cd class
$ pyenv virtualenv 3.4.3 tmp-py-class
$ pyenv local tmp-py-class
$ pip install --upgrade pip
$ pip list

클래스 (class)

객체 지향 프로그래밍

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

클래스라는 객체 타입이다.

클래스

클래스는 객체를 만들기 위한 틀이다. (현실에 비유할 경우, 붕어빵과 붕어빵 틀이라고 생각하는것이 일반적이다)

__init__은 클래스를 사용한 객체의 초기화 메서드이다. 객체를 생성할 때 인자를 어떻게 전달받고, 받은 인자를 이용해 어떤 객체를 생성할 지 정의할 수 있다.

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

# 클래스를 사용해 객체 생성
lotteria = Shop('Lotteria')
print(lotteria.name)

위 코드는 아래 순서로 동작한다.

  1. Shop 클래스가 정의되었는지 찾는다.
  2. Shop 클래스형 객체를 메모리에 생성한다.
  3. 생성한 객체의 초기화 메서드 __init__을 호출한다.
  4. name값을 저장하고, 만들어진 객체를 반환한다.
  5. lotteria변수에 반환된 객체를 할당한다.

객체의 메서드를 정의할 때, 첫 번째 인수는 항상 self이다. self에는 메서드를 호출하는 객체 자신이 자동으로 전달된다. 이렇게 self가 자동으로 호출되는 이유는 클래스의 메서드를 사용할 때 어떤 객체가 해당 메서드를 사용하고 있는지 알 수 있도록 하기 위해서이다. 또한 이렇게 하나의 메서드를 여러 객체가 공유할 수 있다.

class Shop:

    def __init__(self, name):
        self.name = name

    # 객체 안의 함수는 메소드
    # self를 넣지 않으면, 아래의 에러 발생
    def show_info():
        print('상점정보 ({})'.format(self.name))

lotteria = Shop('Lotteria')
# 속성이나 메서드 접근 시,
# 객체.속성명 or 객체.메서드명
print(lotteria.name)
lotteria.show_info()
$ python class_basic.py
Lotteria
Traceback (most recent call last):
  File "class_basic.py", line 11, in <module>
    lotteria.show_info()
TypeError: show_info() takes 0 positional arguments but 1 was given
class Shop:

    def __init__(self, name):
        self.name = name

    # 인스턴스가 여러 개여도 self덕에 알 수 있다.
    def show_info(self):
        print('상점정보 ({})'.format(self.name))

lotteria = Shop('Lotteria')
print(lotteria.name)
lotteria.show_info()
$ python class_basic.py
Lotteria
상점정보 (Lotteria)

클래스 속성

어떤 하나의 클래스로부터 생성된 객체들이 같은 값을 가지게 하고 싶을 경우, 클래스 속성(class attribute)를 사용한다.

class Shop:
    # 클래스 속성
    description = 'Python Shop Class'


    def __init__(self, name):
        self.name = name
        # 클래서 속성보다 인스턴스 속성이 우선
        # self.description = '이것은 Shop클래스형 객체입니다.'

    def show_info(self):
        print('상점정보 ({})'.format(self.name))

# Class이름() : 생성자
# 생성자 > 인스턴스(lotteria) 생성 > 호출됨과 동시에 init을 호출 > 생성된 인스턴스(lotteria)가 self로 전달
lotteria = Shop('Lotteria')
print(lotteria.description)

bugerking = Shop('Bugerking')
print(bugerking.description)
$ python class_basic.py
Python Shop Class
Python Shop Class

마찬가지로, 객체들에게서 각각의 인스턴스와는 별개의 공통된 메서드를 사용하게 하고 싶을 경우 클래스 메서드(class method)를 사용한다.

메서드

인스턴스 메서드

인스턴스 메서드는 첫 번째 인수로 self를 가진다. 인스턴스를 이용해 메서드를 호출할 때 호출한 인스턴스가 자동으로 전달되며, 전달받은 인스턴스는 상태를 확인하거나 조작하는데에 사용된다.

class Shop:
    description = 'Python Shop Class'

    def __init__(self, name, shop_type, address):
        self.name = name
        self.shop_type = shop_type
        self.address = address

    def show_info(self):
        print('상점정보 ({})\n  유형: {}\n  주소: {}'.format(self.name, self.shop_type, self.address))

    def change_type(self, new_type):
        self.shop_type = new_type


shop1 = Shop('롯데리아', '패스트푸드', '서울시 강남구')
shop1.show_info()
shop1.change_type('레스토랑')
shop1.show_info()
$ python class_basic.py
상점정보 (롯데리아)
  유형: 패스트푸드
  주소: 서울시 강남구
상점정보 (롯데리아)
  유형: 레스토랑
  주소: 서울시 강남구

클래스 메서드

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

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

class Shop:
    description = 'Python Shop Class'

    def __init__(self, name, shop_type, address):
        self.name = name
        self.shop_type = shop_type
        self.address = address

    @classmethod
    def change_description(cls, new_description):
        cls.description = new_description

shop1.change_description('인스턴스를 통해 호출함')
print(shop1.description)
Shop.change_description('클래스트를 통해 호출함')
print(Shop.description)
$ python class_basic.py
인스턴스를 통해 호출함
클래스트를 통해 호출함

스태틱 메서드

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

class Shop:
    description = 'Python Shop Class'

    def __init__(self, name, shop_type, address):
        self.name = name
        self.shop_type = shop_type
        self.address = address

    @staticmethod
    def print_test():
        print('staticmethod test!')

shop1.print_test()
$ python class_basic.py
staticmethod test!

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

캡슐화

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

예를 들어 유저(lim_user)의 속성에 cash가 있을 경우, lim_user.cash=10000해서 문제가 생길 수 있다. 그래서 정보를 은닉하기 위해 캡슐화를 한다.

change_type메서드나 change_description클래스 메서드를 사용하지 않고도 내부 내용을 변경할 수 있다.

class Shop:
    def __init__(self, name, shop_type, address):
        self.name = name
        self.__shop_type = shop_type
        self.address = address

    def show_info(self):
        print('상점정보 ({})\n  유형: {}\n  주소: {}'.format(self.name, self.__shop_type, self.address))

    def change_type(self, new_type):
        self.shop_type = new_type

shop1 = Shop('롯데리아', '패스트푸드', '서울시 강남구')
shop1.address = '미국'
print(shop1.address)
shop1.show_info()
$ python class_basic.py
미국
상점정보 (롯데리아)
  유형: 패스트푸드
  주소: 미국

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

class Shop:
    def __init__(self, name, shop_type, address):
        self.name = name
        self.__shop_type = shop_type
        self.address = address

    def show_info(self):
        print('상점정보 ({})\n  유형: {}\n  주소: {}'.format(self.name, self.__shop_type, self.address))

    def change_type(self, new_type):
        self.shop_type = new_type

shop1 = Shop('롯데리아', '패스트푸드', '서울시 강남구')
print('__shop_type' in dir(shop1))
print('name' in dir(shop1))
# shop1이 가진 속성과 메소드 확인
for item in dir(shop1):
    print(item)
shop1.__shop_type = 'new type test'
print('===')
# 실제 이름은 _<클래스명>__<속성명>으로 변경
print(shop1._Shop__shop_type)
$ python class_basic.py
False
True
# shop1이 가진 속성과 메소드 확인
_Shop__shop_type
__class__
__delattr__
__dict__
__dir__
__doc__
__eq__
__format__
__ge__
__getattribute__
__gt__
__hash__
__init__
__le__
__lt__
__module__
__ne__
__new__
__reduce__
__reduce_ex__
__repr__
__setattr__
__sizeof__
__str__
__subclasshook__
__weakref__
address
change_description
change_type
name
print_test
show_info
===
패스트푸드

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

get/set속성 값과 property

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

파이썬에서는 해당 기능을 프로퍼티(property)를 사용해 간편히 구현한다.

setter프로퍼티를 명시하지 않으면 읽기전용이 되어 외부에서 조작할 수 없게 된다.

class Shop:

    def __init__(self, name, address):
        self.__name = name
        self.__address = address

    # 다른 언어에서 사용하는 형식 getter, setter
    def get_name(self):
        return self.__name

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

    # 파이썬에서는 property를 사용
    @property
    def name(self):
        return self.__name

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


shop1 = Shop('롯데리아', '서울시 강남구')
shop1.get_name()
shop1.set_name('bugerking')

shop2 = Shop('맥도날드', '서울시 논현동')
# property에 접근할 때,
# 속성을 쓰는 것처럼 사용한다.
print(shop2.name)
shop2.name = '버거킹'

상속

거의 비슷한 기능을 수행하나, 약간의 추가적인 기능이 필요한 다른 클래스가 필요할 경우 기존의 클래스를 상속받은 새 클래스를 사용하는 형태로 문제를 해결할 수 있다.

이 때, 상속 되는 클래스를 부모(상위)클래스라고 하며, 상속을 받는 클래스는 자식(하위)클래스라고 한다.

상속을 받을때는 클래스의 정의 다음 괄호에 부모 클래스를 적어주면 된다.

class Restaurant(Shop):
    pass

상속받은 클래스는 부모 클래스의 모든 속성과 메서드를 사용할 수 있다.

QnA

  • property는 속성처럼 사용할 수 있기 때문에 type해도 str이 반환
  • staticmethod는 일반 함수와 비슷한데, 클래스 안에서만 쓸수 있다. 아무도 조작하지 못한다. (많이 사용하지는 않음)