[Python] 가끔 저지른 실수들

Python 코딩하면서 겪게 된 실수를 한번 정리해 볼까.

1. tab indentation

아마도 들여쓰기(indent)를 탭(Tab)이 아닌 공백(space)으로 하다보면 가끔 발생하는 문제가 tab이 섞여서 나타나는 오류다. 물론 쉽게 해결이 가능하긴 하지만 가끔 들여쓰기 레벨이 틀려져서 곤란해졌던 경험이 자주 있다.

개인적으로 다음 설정을 Vim에 넣어서 해결하긴 한다. (탭은 공백으로, 크기는 4인 경우)
map <leader>ts <ESC>:%s/\t/    /g
\ts를 누르면 탭을 공백4개로 바꿔버린다. 약간 위험하긴 하지만… –_–; 슬래쉬랑 슬래쉬 사이에 공백이 들어있는건 4개의 스페이스인데 혹시나 해서 언급…

Vim에서 smartindent를 켜 둔 상태라면 자동으로 들여쓰기가 되면서 tab이 섞여들어갈 가능성이 있다. 주의…


2. None

type()을 이용할 때 종종 했던 실수는 None을 체크하는 것.
예전에도 언급했지만 한번 더 언급하자. None의 타입 이름은 ‘None'이 아니라 'NoneType'이다.
>>> type(None).__name__
'NoneType'

3. datetime

datetime 자료구조를 이용하기 위해 import할 때가 있는데 datetime은 모듈이름이지 바로 써 먹는 녀석이 아니라는 점
>>> import datetime
>>> dt = datetime(1979, 4, 20)
  Traceback (most recent call last):
    File "", line 1, in 
      dt = datetime(1979, 4, 20)
TypeError: 'module' object is not callable
이름이 겹치기 때문에 그렇겠지만, datetime은 datetime안에 있는 datetime이다. (어우 짜증나…)
>>> dt = datetime.datetime(1979, 4, 20)
>>> dt
datetime.datetime(1979, 4, 20, 0, 0)
왜 이런식으로 구성했는가 했더만 datetime 모듈에서는 datetime 뿐만 아니라 date 및 time형식의 자료구조도 따로 존재했던 것이었다… 어휴 –_–

4. import … as …

이건 실수라기 보단 무지에 가깝지만…

Django로 개발을 하다 보면 PYTHONPATH의 존재 덕분에 AppName.Module 형식으로 import를 하게 되는 경우가 많다. 지극히 좋은 방법이긴 하다. from … import * 같은 형태로 모든 symbol을 import해 버리면 namespace가 꼬여버릴 수도 있으니 말이다.

하지만 as문의 존재를 몰랐던 때는 다른 앱에서 특정 앱의 aaaaaaa모듈의 b의 ccc()를 엑세스 하기 위해 import aaaaaaa.b로 import해서 aaaaaaa.b.ccc()같은 식으로 무식하게(길게) 호출하는 삽질을 했던 적도 있다.
import aaaaaaa.b as b
이 문법을 안 뒤로 수 많은 코드 비호환성 문제로 겪었던 노가다 코드를 날려버릴 수 있었고 …울었다…

5. unicode vs utf-8

unicode의 정의를 제대로 파악하지 못 했던 때의 실수이긴 하다.

Vim이 utf-8 인코딩으로 동작하는 터라 unicode 문자열(u'…‘)과 utf-8 문자열(’…‘)이 섞일 때 종종 문제를 겪었다. 뿐만 아니라 formatted 문법이라고 하던가(C의 %s, %d 같은거) 이런걸 쓸 때도 인코딩이 얽히면서 Exception이 발생하는데 원인을 못 찾아서 고생했었다.

이후로 문자열을 u'…‘형식으로 쓰는게 습관화 되었는데 그래서 utf-8문자열을 일부러 출력해야 되는 경우에는 낭패를 겪기도 하고 그저 울 뿐이었다. 그냥 utf-8으로 통일하면 안될까? ;;

6. os.popen

터미널 설정에서 LANG은 utf-8이고 실행시키려는 스크립트가 뱉어내는 문자열도 utf-8일 때, 서버에서 os.popen으로 해당 스크립트를 실행시켜서 결과를 읽어보니 몽땅 깨지는 거다.

왜 이럴까 했는데 사실 이건 python의 문제가 아니더라. 실행시키는 서버 환경이 Django다 보니 Apache의 LANG에 말려들어갔던 문제였다. 그냥 스크립트 실행시킬 때 앞에 LANG=‘utf-8'이라고 강제로 적어줘서 해결했던 경험.

왜 이걸 언급하냐하면 os.popen의 문제가 아니라는 것을 빨리 파악하라는 것. ;; (더불어 Django의 unit-test는 사용자 터미널 환경에서 구동되지만 실제 서비스는 어떻게 구성했느냐에 따라 사용자 터미널과는 다를 가능성이 높다는 것을 인지해야 된다)

7. eval()

분명 eval()은 스트링 문자열을 실행시킬 수 있는 함수인데 항상 제대로 동작하지 않았다. parameter를 문자열 안에 같이 썼기 때문에 문제였지. eval(str)(parameters…)형식으로 구동해야 된다는 걸 잘 알게 되었다.

하지만 eval()의 경우처럼 eval()()형식으로 실행시키는 건 익숙하지 않아서 종종 실수한다. eval(str, (parameters)) 이런 식으로 쓴다던가… 물론 eval()을 써서 보안성을 떨어뜨리는 실수는 애초에 막는게 좋다.;;

8. Syntax Error

누구나 자주 경험하는 오타 문제. 근데 원인을 찾기 힘든게 다반수. 원인을 찾기 쉬웠다면 진작에 고쳤을테니까.

대체로 dict를 구성하는데 문자열에 쿼터(‘’)로 묶어주는걸 깜빡했다거나, 콜론(:) 대신 리스트 처럼 콤마(,)를 찍었다던가…

9. return

Python의 유용한 점 하나가 tuple이다. return 시에도 tuple을 리턴할 수가 있다. 하지만 이것 때문에 문제가 발생할 경우를 잘 알아야 한다. 왜냐하면 그냥 겉으로 봐선 tuple을 리턴하는지 파악이 안되기 때문이지.

Django의 get_or_create()는 악마의 함수다. 편하지만 튜플을 리턴하는 것 때문에 속을 너무 썩혔어…

… 한도 끝도 없네. 여기서 마무리 …

댓글

이 블로그의 인기 게시물

소수점 제거 함수 삼총사 ceil(), floor(), round()

버전(Version)을 제대로 이해하기