코드의 마지막 줄에서 아직 유일하게 분석하지 못한 한가지는 모든 일을 해 주는 코드입니다. 그러나 이제 그 작업은 쉽습니다. 왜냐하면 필요한 모든 것이 필요한 그대로 준비되어 있기 때문입니다. 모든 도미노 조각이 제 자리에 놓였고; 이제 쓰러뜨릴 시간입니다.
다음은 apihelper.py의 핵심입니다:
- print "\n".join(["%s %s" %
- (method.ljust(spacing),
processFunc(str(getattr(object, method).__doc__)))
for method in methodList])
주목할 것은 이는 한 개짜리 명령어로서 여러 줄에 걸쳐 있지만 줄 연속 문자(\)를 사용하지 않는다는 것입니다. 기억하십니까? 어떤 표현식은 역사선을 사용하지 않고서도 여러 줄로 갈라질 수 있습니다. 지능형 리스트가 그런 표현식 중의 하나입니다. 왜냐하면 전체 표현식이 각 괄호 안에 담기어 있기 때문입니다.
이제, 맨뒤에서 지능형 리스트를 뜯어내어 거꾸로 연구해 보겠습니다.
for method in methodList위는 지능형 리스트(list comprehension)를 보여줍니다. 아시다시피, methodList는 리스트로서 object에서 관심을 두고 있는 모든 메쏘드를 담고 있습니다. 그래서 method로 그 리스트를 회돌이하고 있습니다.
예제 4.22. 동적으로 문서화 문자열(doc string) 얻는 법
- >>> import odbchelper
- >>> object = odbchelper ①
>>> method = 'buildConnectionString' ②
>>> getattr(object, method) ③
>>> print getattr(object, method).__doc__ ④
Build a connection string from a dictionary of parameters.
Returns string.
① info 함수에서, object는 여러분에게 도움을 줄 객체로서, 인자로 건네집니다.
② methodList를 회돌이하는 동안, method는 현재 메쏘드의 이름입니다.
③ getattr 함수를 사용하여, object 모듈에 있는 method 함수를 가리키는 참조점을 얻고 있습니다.
④ 이제, 메쏘드의 실제 문서화 문자열(doc string)을 쉽게 인쇄할 수 있습니다.
다음 퍼즐 조각은 str을 문서화 문자열(doc string) 둘레에 사용하는 것입니다. 기억하시겠지만, str은 데이터를 문자열로 바꾸는 내장 함수입니다. 그러나 문서화 문자열(doc string)은 언제나 문자열입니다. 그런데 왜 str 함수에 신경을 쓸까요? 그 해답은 어느 함수나 다 문서화 문자열(doc string)을 가지고 있는 것은 아니기 때문입니다. 만약 그렇다면 __doc__ 속성이 None이 되기 때문입니다.
예제 4.23. 왜 문서화 문자열(doc string)에 str 함수를 사용하는가?
- >>> >>> def foo(): print 2
- >>> >>> foo()
2
>>> >>> foo.__doc__ ①
>>> foo.__doc__ == None ②
True
>>> str(foo.__doc__) ③
'None'
① 문서화 문자열(doc string) 없이 함수를 정의하기가 쉽습니다. 그래서, 그의 __doc__ 속성은 None입니다. 혼란스럽게도, __doc__ 속성을 곧바로 평가하면 파이썬 IDE는 아무것도 인쇄하지 않습니다. 생각해 보면 일리는 있지만, 여전히 도움은 안됩니다.
② __doc__ 속성의 값이 실제로 None이라는 것을 직접 비교해 보면 알 수 있습니다.
③ str 함수는 'None'의 널 값을 받아 문자열 표현을 돌려줍니다.
☞ SQL에서는 널 값을 비교하려면 = NULL 대신에 IS NULL을 사용해야 합니다. 파이썬에서는 == None 또는 is None을 사용할 수 있지만, is None이 더 빠릅니다.
이제 확실하게 문자열을 확보하였습니다. 그 문자열을 processFunc에 건넬 수 있습니다. 이 함수는 이미 정의해 둔 함수로서 공백문자로 축약하거나 또는 축약하지 않습니다. 이제 str을 사용하여 None 값을 문자열 표현으로 변환하는 것이 왜 중요한지 알 수 있습니다. processFunc는 인자가 문자열이라고 간주하고 자신의 split 메쏘드를 호출합니다. 이럴 경우 None을 건네면 충돌이 일어납니다. 왜냐하면 None은 split 메쏘드가 없기 때문입니다.
뒤로 좀 더 물러서서 보면 문자열 형식화를 또 사용하여 processFunc의 반환값과 method ljust 메쏘드의 반환값을 결합하고 있음을 볼 수 있습니다. ljust 메쏘드는 아직 보지 못한 새로운 문자열 메쏘드입니다.
예제 4.24. ljust 소개
- >>> s = 'buildConnectionString'
- >>> s.ljust(30) ①
'buildConnectionString '
>>> s.ljust(20) ②
'buildConnectionString'
① ljust 메쏘드는 주어진 길이만큼 문자열에 공간문자를 채웁니다. 이를 info 함수가 사용하여 두 개의 컬럼을 출력하며 두 번째 컬럼에 문서화 문자열(doc string)을 모두 정렬합니다.
② 주어진 길이가 문자열의 길이보다 작으면 ljust는 단순히 문자열을 그냥 돌려줍니다. 문자열을 잘라내지 않습니다.
거의 완성입니다. ljust 메쏘드로 메쏘드 이름이 주어지고 processFunc를 호출하여 (축약될 수도 있는) 문서화 문자열(doc string)이 주어지면 그 두 개의 문자열을 결합해 하나의 문자열을 얻습니다. methodList를 짝짓기 하고 있으므로, 결국 문자열 리스트를 얻습니다. 문자열 "\n"의 join 메쏘드를 사용하여, 이 리스트를 한 개짜리 문자열로 결합합니다. 리스트의 각 원소 마다 따로따로 줄을 차지합니다. 그리고 그 결과를 인쇄합니다.
예제 4.25. 리스트 인쇄하기
- >>> li = ['a', 'b', 'c']
- >>> print "\n".join(li) ①
a
b
c
① 이는 리스트와 작업할 때 유용한 디버깅 트릭이기도 합니다. 그리고 파이썬에서는 언제나 리스트로 작업합니다.
이제 마지막 퍼즐 조각입니다. 다음 코드가 이해 되실줄로 믿습니다.
- print "\n".join(["%s %s" %
- (method.ljust(spacing),
- processFunc(str(getattr(object, method).__doc__)))
for method in methodList])
4.9. 요약
apihelper.py 프로그램과 그의 출력은 이제 완벽하게 이해가 되실 겁니다.
- def info(object, spacing=10, collapse=1):
- """Print methods and doc strings.
Takes module, class, list, dictionary, or string."""
methodList = [method for method in dir(object) if callable(getattr(object, method))]
processFunc = collapse and (lambda s: " ".join(s.split())) or (lambda s: s)
print "\n".join(["%s %s" %
(method.ljust(spacing),
processFunc(str(getattr(object, method).__doc__)))
for method in methodList])
if __name__ == "__main__":
print info.__doc__
다음은 apihelper.py의 출력입니다:
- >>> from apihelper import info
- >>> li = []
>>> info(li)
append L.append(object) -- append object to end
count L.count(value) -> integer -- return number of occurrences of value
extend L.extend(list) -- extend list by appending list elements
index L.index(value) -> integer -- return index of first occurrence of value
insert L.insert(index, object) -- insert object before index
pop L.pop([index]) -> item -- remove and return item at index (default last)
remove L.remove(value) -- remove first occurrence of value
reverse L.reverse() -- reverse *IN PLACE*
sort L.sort([cmpfunc]) -- sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1
'Python' 카테고리의 다른 글
5. 객체 그리고 객체-지향 (0) | 2012.01.12 |
---|---|
pdgmail source code (0) | 2012.01.11 |
4.7. lambda 함수 사용하기 (0) | 2012.01.11 |
4.6. and와 or의 특이한 본성 (0) | 2012.01.11 |
4.4. getattr로 객체 참조점 얻는 방법 (0) | 2012.01.11 |