python 가상환경 만들기

|
  • pyenv
    • 로컬에 다양한 파이썬 버전을 설치하고 사용할 수 있도록 한다. pyenv를 사용함으로써 파이썬 버전에 대한 의존성을 해결할 수 있다.
  • virtualenv
    • 로컬에 다양한 파이썬 환경을 구축하고 사용할 수 있도록 한다.
  • autoenv
    • 특정 프로젝트 폴더로 들어가면 자동으로 개발 환경을 설정해주는 스크립트

pyenv 깔기

brew install pyenv
brew upgrade pyenv --HEAD
brew install openssl readline xz

pyenv에 지원하는 python list 살펴보기

pyenv versions

새로운 python 깔기

pyenv install 3.5.1

만약 zlib 관련 에러가 난다면 xcode-select --install로 개발자 툴을 업데이트하자

pyenv-virtualenv 깔기

brew install pyenv-virtualenv  

이후 bash_profile에 다음 줄을 추가한다.

eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"

pyenv-virtualenv 사용하기

pyenv virtualenv 3.5.1 pyView-3.5.1하면 3.5.1버전으로 pyView-3.5.1 가상환경을 만든다.

이제 pyenv shell pyView-3.5.1로 가상환경을 사용가능하다.

autoenv를 자동으로 실행

brew install autoenv

bash_profile에 다음을 추가하면 폴더의 .env가 존재할 경우 실행시켜준다.

source /usr/local/opt/autoenv/activate.sh

make .env

#~/Git/math-logic-server/.env

pyenv shell mathServer-3.5.1

요렇게 만들면 폴더에 들어가면서 자동으로 python을 바꿔준다. 물론 이는 내 클라이언트에만 해당하니 git에 올리지 않는 것이 좋다.

Python Class Master

|

원문

Class

python에서는 class 또한 object이다. 아래는 다른 언어와 비슷한 용도로 class를 쓰는 방법이다.

class ObjectCreator(object):
    pass
  
my_object = ObjectCreator()

print(my_object)
# <__main__.ObjectCreator object at 0x8974f2c>

위처럼 class는 object를 생성할 수 있는 녀석이지만 말했듯이 object이기 때문에 다음과 같은 것이 가능하다

  • variable을 assign 가능
  • copy가 가능
  • attribute를 추가할 수 있음
  • function의 parameter로 넘길 수 있음
### class또한 object이기 때문에 print  가능! ###
print(ObjectCreator) 
#<class '__main__.ObjectCreator'>
def echo(o):
    print(o)
    
### 함수의 파라미터로 넘길 수도 있다. ###
echo(ObjectCreator) 
# <class '__main__.ObjectCreator'>

### 새로운 attribute를 추가할 수 있다. ###
print(hasattr(ObjectCreator, 'new_attribute'))
# False
ObjectCreator.new_attribute = 'foo' 
print(hasattr(ObjectCreator, 'new_attribute'))
# True
print(ObjectCreator.new_attribute)
# foo

### class를 variable에 assign 가능하다. ###
ObjectCreatorMirror = ObjectCreator
print(ObjectCreatorMirror.new_attribute)
# foo
print(ObjectCreatorMirror())
# <__main__.ObjectCreator object at 0x8997b4c>

Creating classes dynamically

class가 object이기 때문에 다이나믹하게 class를 만들 수 있다. 다음은 예제코드이다

def choose_class(name):
    if name == 'foo':
        class Foo(object):
            pass
        return Foo # instance가 아닌 class를 return
    else:
        class Bar(object):
            pass
        return Bar
    
MyClass = choose_class('foo') 
print(MyClass) # 함수가 instance가 아닌 class를 리턴한다.
#<class '__main__.Foo'>
print(MyClass()) # return받은 class로 instance를 만들 수 있다.
#<__main__.Foo object at 0x89c6d4c>

예제를 보면 유기적으로 class를 만들지만 좀 복잡해보인다. class 선언문을 그대로 집어넣었는데 이를 바꿔볼 순 없나??

그래서 python에서는 type 함수를 지원한다.이 함수는 용법이 다음과 같다.

type(만들 class의 이름, --(1)
     부모 class들의 tuple, --(2) 
     attribute를 위한 dictionary) --(3)

(1) : 정확히 얘기하자면 만들 class.__name__에 들어갈 속성을 의미한다. 보통 class 이름과 같이 쓰고 헷갈리지 않기 위해 이를 지켜주자.

(2) : parent class들의 tuple인데 빈 tuple이 될 수도 있다.

(3) : attribute가 들어간다.

사실 python에 type 함수는 어떤 object의 type을 알아보기 위해서도 쓰는데 역할이 다른 하나의 함수는 python에서 보기 힘들다. 이는 예전 호환성을 지키기 위함이고 다른 function이라 생각하자.

type 함수를 이용하여 class를 만들어보자!

class Foo(object):
    bar = True

class FooChild(Foo):
    pass

#위와 같은 것은

Foo = type('Foo', (), {'bar':True})
FooChild = type('FooChild', (Foo,), {})

print(FooChild.bar)
# True

생성 시 attribute 넣기

위의 class에 attribute를 넣을 수 있다.

def echo_bar(self):
    print(self.bar)
FooChild = type('FooChild', (Foo,), {'echo_bar': echo_bar})
hasattr(Foo, 'echo_bar')
# False
hasattr(FooChild, 'echo_bar')
# True
my_foo = FooChild()
my_foo.echo_bar()
# True

이미 존재하는 class에 attribute를 추가하기

def echo_bar_more(self):
    print('yet another method')

FooChild.echo_bar_more = echo_bar_more
hasattr(FooChild, 'echo_bar_more')
# True

Python custom class에서 array처럼 접근하기!

|
class testClass():
    def __init__(self):
        self.dataList = [1,2,3,4,5]
    def __getitem__(self, key):
        return self.dataList[key]

a = testClass()
a[1]
# 2
a[2]
# 3

MetaClass - class의 class!

|

#Meta class

Metaclass란?

class를 만드는 어떠한 것. class : instance = metaclass : class로 볼 수 있다.

MyClass = MetaClass()
MyObject = MyClass()

우리는 python Class Master에서 type함수가 class를 만드는 것을 보았다.

MyClass = type('MyClass', (), {})

type함수는 사실 metaclass이며, python에서는 class를 만들기 위해, 속에서는 type을 이용하여 class를 만든다.

파이썬의 모든 것은 object이며, 모두 class로부터 나온다.

age = 35
age.__class__
#<type 'int'>

name = 'bob'
name.__class__
#<type 'str'>

def foo(): pass
foo.__class__
#<type 'function'>

class Bar(object): pass
b = Bar()
b.__class__
#<class '__main__.Bar'>

또한 이 모든 object의 metaclass는 default로 type이다.

>>> age.__class__.__class__
<type 'type'>
>>> name.__class__.__class__
<type 'type'>
>>> foo.__class__.__class__
<type 'type'>
>>> b.__class__.__class__
<type 'type'>

metaclass

class를 만들 때 __metaclass__ attribute를 넣으면 해당 class를 만들기 위해 이 attribute를 쓴다.

class Foo(object):
  __metaclass__ = something...
  [...]

__metaclass__를 찾는 순서는 다음과 같다.

  1. class__metaclass__가 존재한다면 가져다 쓴다.
  2. 존재하지 않는다면 자기 모듈에서 찾는다.(아무것도 상속받지 않는 경우)
  3. 부모 class중 첫번째 녀석의 __metaclass__를 가져다쓴다.(상속을 받는 경우)

custom metaclass

모든 attribute가 Upper case인 class를 만들 때…

def upper_attr(future_class_name, future_class_parents, future_class_attr):
  uppercase_attr = {}
  for name, val in future_class_attr.items():
      if not name.startswith('__'):
          uppercase_attr[name.upper()] = val
      else:
          uppercase_attr[name] = val
  return type(future_class_name, future_class_parents, uppercase_attr)

__metaclass__ = upper_attr # 이 녀석이 있어서 해당 파일의 모든 class가 이 녀석을 씀

class Foo(): 
  bar = 'bip'

print(hasattr(Foo, 'bar'))
# Out: False
print(hasattr(Foo, 'BAR'))
# Out: True

f = Foo()
print(f.BAR)
# Out: 'bip'

다음은 type을 상속받아 만드는 예제이다.

class UpperAttrMetaclass(type): 
    # __new__: __init__전에 불리는 함수. object를 만들고 return한다.
    def __new__(cls, clsname, bases, dct):

        uppercase_attr = {}
        for name, val in dct.items():
            if not name.startswith('__'):
                uppercase_attr[name.upper()] = val
            else:
                uppercase_attr[name] = val

        return super(UpperAttrMetaclass, cls).__new__(cls, clsname, bases, uppercase_attr)

kargs, args

|

*args

파라미터를 몇개 받을 지 모르는 경우 사용한다. 튜플 형태로 전달된다.

def print_param(*args):
    print args
    for p in args:
        print p
 
print_param('a', 'b', 'c', 'd')
#('a', 'b', 'c', 'd')
#a
#b
#c
#d

**kwargs

파라미터 명을 같이 보낼 수 있다. 딕셔너리형태로 전달된다.

def print_param2(**kwargs):
    print kwargs
    print kwargs.keys()
    print kwargs.values()
 
    for name, value in kwargs.items():
        print "%s : %s" % (name, value)
 
print_param2(first = 'a', second = 'b', third = 'c', fourth = 'd')
 
#{'second': 'b', 'fourth': 'd', 'third': 'c', 'first': 'a'}
#['second', 'fourth', 'third', 'first']
#['b', 'd', 'c', 'a']
#second : b
#fourth : d
#third : c
#first : a

나머지…

def print_param3(*args, **kwargs):
    print args
    print kwargs
 
print_param3('a', 'b')
#('a', 'b')
#{}
 
print_param3(third = 'c', fourth = 'd')
#()
#{'fourth': 'd', 'third': 'c'}
 
print_param3('a', 'b', third = 'c', fourth = 'd')
#('a', 'b')
#{'fourth': 'd', 'third': 'c'}

함수의 인자로 List에 *를 붙이면 position arguments로 함수에 집어넣은 것과 똑같은 의미를 갖는다. Dictionary의 경우 **를 붙이면 keyword arguments로 함수에 집어넣은 것과 같은 의미이다.

def print_param4(a, b, c):
    print a, b, c
 
p = ['a', 'b', 'c']
print_param4(*p)
#a b c
 
p2 = {'c' : '1', 'a' : '2', 'b' : '3'}
print_param4(**p2)
#2 3 1