howdoi 패키지 읽기

읽은 코드: howdoi 패키지 https://github.com/gleitz/howdoi

지난 학기에 랩실 선배랑 협업(이 아니라 초딩과 빨간펜 선생님의 첨삭 수준..)을 했는데, 내 허접한데 복잡한… 코드를 선배가 바꿔놓는걸 즉각적으로 보며.. 잘하는 남이 어떻게 코드를 짰나 보는게 공부가 많이 된다고 느꼈다. 게다가 협업은 남 코드 읽고 이해하는게 8할인 거 같고.. 세상에 좋은 코드는 많은 것 같고.. 해서 남의 코드 공부를 좀 해볼 것이다.

책은 ‘파이썬을 여행하는 히치하이커를 위한 안내서’를 참고했다.

Overall

커맨드라인에서 질문을 입력받고, 그에 대한 웹상의 답을 출력하는 라이브러리이다.

전체적인 흐름을 설명하자면 다음과 같다.
커맨드라인에서 쿼리를 받아서, 그 쿼리 결과에 해당하는 스택오버플로 링크를 얻는다. 그리고 사용자가 원하는 답변 개수만큼, 답변을 파싱하는 get_answer를 wrapper 함수 get_answers에서 돌리고, get_answers가 반환하는 답변의 리스트를 터미널에 출력한다.
커맨드라인에서 파싱하는 get_parser부터 get_answers까지 howdoi 함수로 또 싸여져있고, 결과적으로 command_line_runner() 함수에서는 쿼리에 대해 답을 출력하는 부분은 howdoi 함수를 실행하는 것으로 끝난다.

실행파일이 하나인데다 코드 순서가 호출 순서(정확히 말하면 역순)로 되어있어서 쭉 이름만 보고 대충 어떤 흐름인지 알 수 있었다. 거의 모든 함수가 한 가지 기능을 하고있고, 함수 네이밍이 가히 예술적이었다…

Lessons learned

  1. 파이썬 및 의존성 버전 차이를 초반에 다 처리함. 유니코드 핸들링하는 함수 u의 형성자체가 컨디션에 종속.
    # Handle imports for Python 2 and 3
     if sys.version < '3':
         import codecs
         from urllib import quote as url_quote
         from urllib import getproxies
         from urlparse import urlparse, parse_qs
    
         # Handling Unicode: http://stackoverflow.com/a/6633040/305414
         def u(x):
             return codecs.unicode_escape_decode(x)[0]
     else:
         from urllib.request import getproxies
         from urllib.parse import quote as url_quote, urlparse, parse_qs
    
         def u(x):
             return x
    
  2. a function name beginning with a single underscore: 딴 데서 import 안할 거고 내부에서만 쓸 거라는 암묵적 약속.
    참고: PEP 8 – Style Guide for Python Code
    • single trailing underscore: 파이썬 키워드와 충돌 피하기 위해 붙임
    • double leading underscore: class attribute 네이밍
    • double leading and trailing underscore: 매직 메소드에만 붙임
  3. formatting
    _print_err('Unsupported engine.\nThe supported engines are: %s' % ', '.join(SUPPORTED_SEARCH_ENGINES))
    
  4. #noqa: stands for ‘no quality assurance’. 린터한테 이 라인 체크하지 말라는 표시
  5. 당연한 말이지만 assign function to a variable 가능
    _print_ok = print
    
  6. 아무것도 없는 ‘return’의 역할: loop에서 break와 비슷
  7. if 많이 쓰는걸 거리낄 필요 없음. 여기서 command_line_runner()에서 플래그(save, help, version..) 입력받았을 때는 앞에서 다 if로 처리하고 그때그때 return 날림. 그리고 마지막에 쿼리 답찾기 위해 howdoi 함수 호출함.
  8. vars 함수: 빌트인으로, 객체 받아서 __dict__으로 만들어줌.