본문 바로가기

더 나은 엔지니어가 되기 위해/파이썬을 파이썬스럽게

파이썬 초급, 그 다음 단계

내가 파이썬을 처음 접해본 것은, 대학교 3학년 컴퓨팅 사고력 멘토를 처음 들어갔을 때다.

학교에 필수교양으로 이제 막 '컴퓨팅 사고력' 이 엄청나게 열리던 시기였고, 컴퓨터 공학과에서 엄청나게 많은 멘토모집을 했었다.

멘토 시급이 엄청 높아서, 나를 비롯한 대부분의 컴공 친구들이 파이썬을 잘 몰라도, 일단 지원하고 보았다.

그리고 수업 일주일 전에 받는 강의 ppt 로 파이썬을 공부했다.

그렇게 난 2년 정도 파이썬 멘토를 하였고, 강의교재 수준의 파이썬은 쉽게 다룰 수 있었다.

부끄럽지만, 내가 알고있는 파이썬은 이 정도 였다.

최근 K사에서 단기 인턴을 하는 동안, 무수히 많은 파이썬으로 짜인 코드들을 보았고, 내 파이썬 문법실력이 얼마나 빈약한지를 깨달았다.

일할 때는 일일이 stack overflow 에서 찾아보다가, 이제라도 뒤늦게 나마 꽤 괜찮은 문서를 찾아 이를 정리해본다.

파이썬 기초가 어느정도 손에 익은 사람이라면, 꼭 도움이 될만한 내용들이 아래 사이트에 정리되어있다. (번역도 훌륭하다.)

링크 : https://ddanggle.gitbooks.io/interpy-kr/content/

파이썬 중급이라고 소개가 되어있지만, 중급까지는 아닌거 같고, 딱 초보와 중급 그 중간 수준인듯 하다.

여기에는 각 내용들의 주요 키워드만 빠르게 적어놓는다. 자세한 내용은 위 링크 참조

내용과 주요 키워드

1. *args 와 **kwargs

둘 모두, 함수 파라미터에 자주 보이는 키워드들인데, 정리하면 다음과 같다.

*args는 키워드 되지않은 가변 갯수의 인자들을 함수에 보낼 때 사용한다.

**kwargs는 키워드된 가변 갯수의 인자들을 함수에 보낼 때 사용한다.

2. 디버깅

python -m pdb my_script.py 로 디버깅 사용 가능.

개인적으로, pycharm 이나 vscode 를 사용하면 더 쉽게 디버깅이 가능하므로, pdb 를 사용할 일은 없을 듯 하다.

3. 제너레이터

메모리와 시간을 중요하게 고려해야하는 상황에서, 반복문을 사용해야할 시 필요한 개념이다.

직관적으로 언제 필요하냐? 대용량 데이터 처리할 때다.

일반적으로, 파이썬은 반복문을 돌 때, 변수를 copy 하여 저장하는데, 이 때, 변수가 잡아먹는 메모리가 매우 클 시, copy 하는 것 자체만으로 문제가 될 수 있다.

제너레이터는, 변수를 copy 하지 않고, 즉시 내보낸다고(?) 한다. 따라서 메모리 효율성이 확 높아진다고 하는데, 자세히 읽어보면 좋다.

4. map, filter

둘 다 파이썬 내장 함수인데, 리스트를 인풋으로 주면, 각 리스트의 아이템 대상으로 어떤 연산(함수)을 하여 반환하거나 (이게 map), 각 리스트에서 특정 아이템들만 걸러서 리스트로 반환한다. (이게 filter)

map(functions_to_apply, list_of_inputs)
filter(functions_to_apply, list_of_inputs)

예를 들면,

items = [1, 2, 3, 4, 5]
squared = map(lambda x : x**2, items)
# squared = [1, 4, 9, 16, 25]

num_list = filter(lambda x: x<3, items)
# num_list = [1, 2]

재밌는건, map의 list_of_input 으로 함수 리스트를 줄 수 있다는 것이다.

에를 들면 아래와 같은 방식이다.

def multiply(x):
   return (x*x)

def add(x):
   return (x+x)

funcs = [multiply, add]
for i in range(5):
   value = map(lambda x: x(i), funcs)

5. Set

이미 널리 알려져있고, 잘 쓰고 있었으므로 패스.

6. 삼항 연산자

이번 기회에 제대로 익히고 가자.

condition_is_true if condition_ture else condition_is_false

7. 데코레이터 (@)

오픈 소스를 써본 경험이 있으면, 자주 봤을만한 녀석이다.

짧게 느낌만 요약하자면,

def decorator(a_func):
 @wraps(a_func)
 def wrapTheFunction():
   print "a_func()가 실행되기 전"
   a_func()
   print "a_func()가 실행된 후"
 return wrapTheFunction

@decorator
def func():
 print "저는 함수입니다."
 
func()

# output :
# a_func()가 실행되기 전
# 저는 함수입니다.
# a_func()가 실행된 후

어떤 함수 func 가 실행 되기 전 후로, 어떤 일을 일관성 있게 하고 싶은데, 이 때 이 '어떤 일'을 하는 함수가 데코레이터 함수 decorator 이고, 어떤 함수 func 위에 데코레이터 함수 @decorator 를 붙여주면 이를 동작하게 하는 문법이, 바로 데코레이터 문법이다.

서비스 목적용 서버에서, 유저의 요청에 특정 함수를 돌리기 전에, 유저가 일반유저인지, 관리자인지 먼저 체크하는 등의 액션을 취해야 하는데, 이럴 때 데코레이터 문법이 많이 사용되는 것을 종종 볼 수 있다.

8. Global, Return

전역변수 사용하는 법은 다음과 같다.

def func():
global a
a = 3
 
func()
print(a)

# output:
# 3

9. 변형(Mutation)

파이썬에서 리스트는 mutatable 하고, 튜플은 immutable 하다는 것은 다 알 것이다.

하나 예상 못한 케이스가 있었는데, 예제는 다음과 같았다.

def add_to(num, target=[]):
 target.append(num)
 return target

add_to(1)
# Output: [1]

add_to(2)
# Output: [1, 2]

add_to(3)
# Output: [1, 2, 3]

나같이 잘 몰랐던 사람이라면, 꽤 충격적이다.

함수의 파라미터인 target 이, 함수가 종료된 뒤에도 사라지지 않는 것을 볼 수 있는데, 이는 파라미터의 타입이 리스트(mutatable한 타입) 이기 때문이란다.

이를 방지하려면, 항상 다음을 준수해야한다고 한다.

def add_to(element, target=None):
 if target is None:
     target = []
     target.append(element)
   return target

10. __slots__

클래스 내 인스턴스 속성의 메모리 관련된 이슈이다.

다음과 같이 __slot__ 에 인스턴스 속성들을 미리 담아두면, 메모리를 훨씬 줄일 수 있다고 한다. (이유는, 인스턴스 속성은 기본적으로 dict 형인데, dict 형이 꽤 무겁다고 한다. dict 형의 경우, 동적으로 메모리 할당이 가능해서 그렇다고. 근데 위 문법을 쓰면 dict 형으로 할당하지 않아서, 메모리가 더 가벼워 지는 것이다.)

class MyClass(object):
   __slots__ = ['name', 'class']

   def __init__(name, class):
       self.name = name
       self.class = class
       self.set_up()
   # ...

11. 가상환경

다 아는 이야기 이므로 패스.

12. Collection 내 자료구조

collection 패키지 내에 쓸만한 자료구조에 대해서 설명해준다. 크게 6가지 있는데, 다음과 같다.

  1. defaultdict

  2. OrderedDict

  3. Counter

  4. deque

  5. namedtuple

  6. enum (얘는 collection이 아니라 enum 에 있지만, 같이 소개됨)

13. enumerate

아직 모르는 사람이 있다면, 익숙해시길. 개인적으로 range 보다 더 파이썬스러운 문법이라고 생각한다.

14. 객체 탐구

객체 내부를 둘러볼 수 있는 파이썬 함수를 소개해준다. 다음과 같다.

  1. dir

  2. type

  3. id

  4. inspect

15. Comprehension

파이썬에서 가장 참신했고, 처음에는 좀 난해했던 문법이 컴프리헨션이다.

특히 인턴했던 K사에서 작업했던 코드들에서 엄청나게 많이 보였는데, 제대로 알아야 응용된 코드들도 한 눈에 볼 수 있는 듯 하다.

요약하면,

var = [item for item in list if item == 2]

몰랐던 부분도 있었는데, 컴프리헨션이 setdict 에도 가능하다는 것이었다.

다음과 같이 사용한다.

# dict
d = {n: n**2 for n in range(5)}

# set
s = {x**2 for x in [1, 1, 2]}

16. Try, Except, Else, Finally

대부분의 언어에는 예외처리 문법이 있는데, 솔직히 학교에서 공부할 때는 이 문법의 중요성을 잘 몰랐다.

K사에서 인턴할 때, 그 중요성을 한번 크게 느꼈는데, 쉽게 죽으면(런타인 에러) 안되는 프로그램을 작성할 때 쓰게된다.

나의 경우, 실시간 로그 수집을 해, json 으로 파싱해서 저장하는, 일종의 실시간 로그수집기를 돌리고 있었는데, 중간에 이상한 형태의 로그가 등장하면 son 파싱이 안되고, 에러가 뜨며 중간에 죽어버렸다. 근데 이 때마다, 재 실행시켜주기도 어렵거니와, 말그대로 '실시간' 로그 수집기였기 때문에, 중간에 죽으면 안되는 상황이었는데, 이 때, 위 문법을 사용할 수 있다는 것을 알았다.

문법을 요약하면,

try 는 예외가 날만한 코드 구간에 적용한다.

except 는 예외가 날 경우, 각 예외 상황 대처에 대한 코드 부분이다.

else 는 예외가 나지 않은 경우, 어떻게 할지에 대한 코드 부분이다. 즉, except 와 else 는 대립적이다.

Finally 는 except, else 둘 중 하나에 뭐가 걸리든, 항상 마무리로 실행하는 코드 부분이다.

17. lambda

익명함수 lambda 는, 주로 filter, map 과 자주 쓰이는데, 이번 기회에 확실히 알고 가도록 하자.

lambda argument : manipulate(argument)

: 를 기준으로 다음과 같이 생각하면 된다.

왼쪽 부분(argument)이 함수의 파라미터, 오른쪽 부분(manipulate)이 함수의 리턴 값

그 외...

마무리 까지 몇 개 안 남긴 했는데, 이 이후로는 문법적인 내용이라기 보단, 알변 좋은 것들 위주로 소개된다.

번역 링크가 아직 작업 중이기도하고, 이후 시간이 되면 추가적으로 정리해보겠다.