앞으로    목차    1    2    3    제4장    5    6    7    8    다음으로

4. 파이썬으로 프로그래밍 하기

4.1. 정지점, 건너뛰기, 등등을 가진 소스 수준의 디버거가 있나요.?

네 있습니다, 모듈 pdb는, 라이브러리 참조 매뉴얼에 문서화된대로, 파이썬을 위한 적절한 기본 디버거입니다. 또한 자신만의 디버거를 pdb용 코드를 예제로 사용하여 작성할 수 있습니다.

또 파이썬윈은 GUI 디버거도 사용가능한데, bdb에 기초하고 있으며, 정지점에 색상을 표현하여 주고 (비-파이썬윈 프로그램을 디버깅하는 것을 포함하여) 상당히 훌륭한 사양을 가지고 있습니다. 인터페이스에 익숙해지려면 약간 수고를 해야 하지만, 그럼에도 불구하고 흥미 있습니다. 참조점은 다음에서 찾아 보실 수 있습니다

    http://www.python.org/ftp/python/pythonwin/pwindex.html
최근의 파이썬윈 버전은 액티브파이썬의 일부로서 사용가능합니다. 다음을 참조 하세요

    http://www.activestate.com/Products/ActivePython/index.html
리차드 울프(Richard Wolff)는 pdb의 변경된 버전을 만들었는데, Pydb라고 불리우며, 인기 있는 데이타 표시 디버거(Data Display Debugger (DDD))에 사용되고 있습니다. Pydb는 다음 http://daikon.tuc.noao.edu/python/에서 찾을 수 있고, 그리고 DDD는 다음 http://www.cs.tu-bs.de/softech/ddd/에서 발견할 수 있습니다.

IDLE의 상호대화적인 개발 환경은, 보통은 표준 배포본의 Tools/idle에서 사용가능한데, 또한 그래픽 디버거를 포함합니다.


4.2. 어떤 메소드는 C로 구현되어 있고 다른 것은 Python으로 구현되어 있는 메쏘드들을 가지고 객체 클래스를 만들 수 있나요 (예. 상속을 통하여)? (다른 말로 하면: 내장 형을 기본 클래스로 사용할 수 있나요?)

안됩니다, 그러나 내장 객체를 둘러싸는 포장자로 기능하는 파이썬 클래스를 쉽게 작성할 수 있습니다, (예. 사전):

        # A user-defined class behaving almost identical
        # to a built-in dictionary.
        class UserDict:
                def __init__(self): self.data = {}
                def __repr__(self): return repr(self.data)
                def __cmp__(self, dict):
                        if type(dict) == type(self.data):
                                return cmp(self.data, dict)
                        else:
                                return cmp(self.data, dict.data)
                def __len__(self): return len(self.data)
                def __getitem__(self, key): return self.data[key]
                def __setitem__(self, key, item): self.data[key] = item
                def __delitem__(self, key): del self.data[key]
                def keys(self): return self.data.keys()
                def items(self): return self.data.items()
                def values(self): return self.data.values()
                def has_key(self, key): return self.data.has_key(key)
A2. 짐 풀튼(Jim Fulton)의 ExtensionClass를 보시면 슈퍼 클래스를 가지도록 허용하는 메카니즘의 예를 보실 수 있는데 파이썬에서 그 슈퍼 클래스로부터 상속받을 수 있습니다 -- 그런식으로 어떤 메쏘드는 C 슈퍼클래스로부터 가질 수 있으며 (이것을 섞어넣기(mixin)이라고 부릅니다) 또 어떤 메쏘드는 파이썬의 슈퍼클래스 혹은 여러분의 하부클래스로부터 가질 수 있습니다. 다음을 참조하세요 http://www.digicool.co m/papers/ExtensionClass.html.

A3. 부스트 파이썬 라이브러리 (BPL, http://www.boost.org/libs/python/doc/index.html)에서는 C++으로부터 이렇게 하는 방법을 제공합니다 (즉. BPL을 사용해서 C++로 작성되어진 확장 클래스로부터 상속받을 수 있습니다).


4.3. 파이썬을 위한 curses/termcap 패키지가 있나요?

표준 파이썬 배포본에 curses 모듈이 따라오는데, Modules/ 하부 디렉토리에 있습니다, 그렇지만 기본 값으로 컴파일 되지 않습니다. 파이썬 2.0 이전 버전에서, 그 모듈은 평범한 curses 만을 지원합니다; 색상을 사용하는 ncurses 사양을 사용할 수는 없습니다. (그렇지만 그것은 ncurses와 연결될 것입니다).

파이썬 2.0에서, curses 모듈은 극적으로 확대되어서, 올리버 안드리히(Oliver Andrich)의 개선된 버전으로부터 시작하여, ncurses와 SYSV curses로부터 온 많은 부가적인 기능들을 제공합니다. 색상, 대체적인 문자 모음 지원, 덧대기, 그리고 마우스 지원과 같은 기능들을 제공합니다. 이것은 곧 그 모듈이 BSD curses만을 가지는 운영체제와 더이상 호환되지 않는다는 것을 의미합니다, 그러나 이 범주에 들어갈 만한 운영체제들이 현재 유지되고 있는 것 같지는 않습니다


4.4. 파이썬 C의 onexit()과 같은 것이 있습니까?

파이썬 2.0에는: 새로운 atexit 모듈이 C의 onexit과 비슷한 등록 함수를 제공합니다. 더 자세한 사항은 라이브러리 참조서를 보세요. 2.0 에 대하여는 sys.exitfunc에 할당해서는 않됩니다!

파이썬 1.5.2에는: sys를 수입하고 함수를 sys.exitfunc에 할당할 필요가 있는데, 그것은 프로그램이 종료할 때, 처리되지 않은 예외에 의하여 사망할때, 혹은 (유닉스에서) SIGHUP 또는 SIGTERMit 신호를 접수할 때 호출될 것입니다.


4.5. 다른 함수안에 내포시켜 한 함수를 정의할 때 그 내포된 함수는 외부의 함수에 있는 지역 변수들에 접근할 수 없는 것 같은데, 왜 그런가요? 어떻게 지역 데이타를 내포된 함수에 건네나요?

파이썬은 임의적으로 내포된 영역을 가지지 않습니다. 지역적으로 사용가능한 어떤 데이타에 접근할 필요가 있는 함수를 작성할 필요가 있을 때는, 새로운 클래스를 만들어서 그 데이타를 유지하고 그 클래스의 실체가 가진 메쏘드를 반환하세요, 예를 들어:

        class MultiplierClass:
            def __init__(self, factor):
                self.factor = factor
            def multiplier(self, argument):
                return argument * self.factor
        def generate_multiplier(factor):
            return MultiplierClass(factor).multiplier
        twice = generate_multiplier(2)
        print twice(10)
        # Output: 20
또 다른 해결책은 기본 인수값을 사용합니다, 예를 들어:

        def generate_multiplier(factor):
            def multiplier(arg, fact = factor):
                return arg*fact
            return multiplier
        twice = generate_multiplier(2)
        print twice(10)
        # Output: 20


4.6. 연속열에 대하여 반대 순서로 어떻게 반복하나요?

만약 리스트라면, 가장 빠른 해결책은 다음과 같습니다

        list.reverse()
        try:
                for x in list:
                        "do something with x"
        finally:
                list.reverse()
이것은 단점이 있는데 그 회돌이 안에 있는 동안에 그 리스트는 임시적으로 역으로 됩니다. 이것이 싫다면, 복사본을 만들 수 있습니다. 이것은 대가가 비싼 것 같이 보이지만 실제적으로는 다른 어떤 해결책들보다 빠릅니다:

        rev = list[:]
        rev.reverse()
        for x in rev:
                <do something with x>
만약 리스트가 아니라면, 더욱 일반적이긴 하지만 더 느린 해결책은 다음과 같습니다:

        for i in range(len(sequence)-1, -1, -1):
                x = sequence[i]
                <do something with x>
더욱 우아한 해결책은, 연속열처럼 행동하고 그 요소들을 역의 순서로 산출하는 클래스를 정의하는 것입니다 (스티브 머제스키(Steve Majewski)의 배려에 의한 해결책):

        class Rev:
                def __init__(self, seq):
                        self.forw = seq
                def __len__(self):
                        return len(self.forw)
                def __getitem__(self, i):
                        return self.forw[-(i + 1)]
이제 간결하게 다음과 같이 작성할 수 있습니다:

        for x in Rev(list):
                <do something with x>
불행하게도, 이 해결책은 이 모든 것중 가장 느립니다, 메쏘드 호출 부담때문에...


4.7. 내 프로그램이 너무 느려요. 어떻게 속도를 올릴 수 있나요?

일반적으로, 어려운 문제입니다. 파이썬 코드의 속도를 높이는 수 많은 꼼수들이 있습니다; 저라면 부분적으로 C로 재작성하는 것을 가장 마지막으로 고려하겠습니다. 주목할 한가지는 함수와 (특히) 메쏘드 호출은 대가가 큽니다; 실체 변수를 획득하거나 설정하는 것 혹은 또 다른 메쏘드를 호출하는 것 이상의 일을 하지 않는, 많은 작은 함수들과의 객체 지향적인 인터페이스를 디자인한다면, 더욱 직접적인 방식의 사용을 고려해도 좋습니다, 예를 들어. 실체 변수들에 직접적으로 접근해도 좋습니다. 또 표준 모듈 "profile"을 참조하시면 (라이브러리 참조 매뉴얼에 설명된대로) 그 모듈로 프로그램이 어느 부분에서 대부분의 시간을 소비하는지를 찾아 낼 수 있습니다 (만약 인내심이 있다면 -- 성능최적화 그 자체는 프로그램의 속도를 엄격한 그 만큼 떨어 뜨립니다).

기억하실 것은 다른 프로그래밍 경험으로부터 알고 있는, 많은 표준 최적화 경험들이 파이썬에도 잘 적용될 수 있다는 것입니다. 예를 들어 커널 시스템 호출의 부담을 피하기 위하여 작은 출력기를 사용하는 것보다 더 큰 출력기를 사용하여 출력 장치에 출력을 보내는 것이 더 빠를 수도 있습니다. 그런식으로 "한 번에" 모든 출력을 써내는 CGI 스크립트가 많은 조각의 출력을 써 내는 스크립트보다 현저하게 더 빠를 수도 있습니다.

또한, 적절한 곳에 확실하게 "집합(aggregate)" 연산을 사용하세요. 예를 들어 "조각 썰기(slicing)" 사양으로 프로그램은, 고도로 최적화된 C 구현을 사용하여, 리스트와 다른 연속열 객체들을 인터프리터의 주회돌이의 한 순간에 썰 수 있습니다. 그리하여 같은 효과를 다음과 같이 얻을 수 있습니다.

  L2 = []
  for i in range[3]:
       L2.append(L1[i])
이것이 사용하기에 훨씬 더 짧고 빠릅니다

  L2 = list(L1[:3]) # "list" is redundant if L1 is a list.
주목할 것은 map() 함수가, 특히 내장 메쏘드 혹은 내장 함수들과 사용되면, 편리한 가속기가 될 수 있다는 것입니다. 예를 들어 두 개의 리스트에 있는 요소들을 함께 짝지으려면:

  >>> map(None, [1,2,3], [4,5,6])
  [(1, 4), (2, 5), (3, 6)]
또는 사인의 수치를 계산하려면:

  >>> map( math.sin, (1,2,3,4))
  [0.841470984808, 0.909297426826, 0.14112000806,   -0.756802495308]
짝짓기 연산은 이러한 경우에 대단히 빠르게 완결됩니다.

집합 연산의 예제에는 문자열 객체의 join과 split 메쏘드가 포함됩니다. 예를 들어 만약 s1..s7 이 거대한 (10K+) 문자열이라면 "".join([s1,s2,s3,s4,s5,s6,s7])은 더 명확해 보이는 s1+s2+s3+s4+s5+s6+s7보다 훨씬 더 빠를 수 있습니다, 왜냐하면 "덧셈"은 많은 하부 표현식을 계산하는 반면에 join은 단 한번에 모든 것을 복사하기 때문입니다. 문자열을 다루려면 또한 정규 표현식 라이브러리를 고려해 보세요. 그리고 "대체(substitution)" 연산 String % tuple 과 String % dictionary를 고려해 보세요. 또한 정렬하기 위해서는 확실하게 list.sort 내장 메쏘드를 사용하세요, 그리고 FAQ의 4.51과 4.59를 보시면 알맞게 개선된 사용법의 예들을 보실 수 있습니다 -- list.sort는 정렬에 관한한 다른 어떤 테크닉보다 뛰어나지만, 대단히 극단적인 환경을 요구합니다.

표준 라이브러리와 공헌된 라이브러리 그리고 확장에는, 다른 많은 집합 연산이 있습니다.

또 다른 일반적인 꼼수는 "회돌이를 함수 혹은 메쏘드 안으로 집어 넣는 것"입니다. 예를 들어 느리게 실행되는 프로그램이 있고 성능최적화기(profiler)를 사용하여 (profile.run) 파이썬 함수 ff가 얼마나 자주 호출되고 있는가 결정한다고 가정해 봅시다. 만약 ff가 다음과 같이

   def ff(x):
       ...do something with x computing result...
       return result
회돌이 안에서 (A)와 같이 호출된다는 것을 알게 되면

   list = map(ff, oldlist)
혹은 (B)와 같이 호출된다는 것을 깨닫게 되면

   for x in sequence:
       value = ff(x)
       ...do something with value...
그러면 다음과 같이 ff를 재작성 함으로써, 함수 호출 부담을 제거할 수 있습니다.

   def ffseq(seq):
       resultseq = []
       for x in seq:
           ...do something with x computing result...
           resultseq.append(result)
       return resultseq
그리고 (A)를 다음과 같이 재작성하거나

    list = ffseq(oldlist)
(B)를 다음과 같이 재작성할 수 있습니다.

    for value in ffseq(sequence):
        ...do something with value...
다른 단순 호출 ff(x)는 아무런 부담없이 ffseq([x])[0]으로 번역됩니다. 물론 이 테크닉은 항상 적절한 것은 아닙니다 그리고 다른 변종들이 있지만, 여러분은 이해 할 수 있습니다.

지역 변수에 대한 함수나 메쏘드의 참조 결과를 명시적으로 저장하면 성능증가를 얻을 수 있습니다. 다음과 같은 회돌이는

    for key in token:
        dict[key] = dict.get(key, 0) + 1
매 반복마다 dict.get을 결정합니다. 만약 그 메쏘드가 변경되지 않는다면, 더 빠른 구현은 다음과 같습니다.

    dict_get = dict.get  # look up the method once
    for key in token:
        dict[key] = dict_get(key, 0) + 1
기본 인수들은 실행시간 대신에 컴파일 시간에 값들을, 결정하는데 한번 사용될 수 있습니다. 프로그램이 실행되는 동안에 변경되지 않을 객체 혹은 함수들에 대해서는 적용될 수 있습니다, 다음과 같이 대체한다면

    def degree_sin(deg):
        return math.sin(deg * math.pi / 180.0)

    def degree_sin(deg, factor = math.pi/180.0, sin = math.sin):
        return sin(deg * factor)
이 꼼수는 기본 인수들을 변경되어서는 안된다는 조건하에 사용하기 때문에, 그것은 사용자에게 혼란스런 API를 제공할 가능성에 대하여 염려되지 않을 때만 사용되어져야 합니다.

최적화에 관련된 일화를 보시려면, 다음을 참조하세요

	essays/list2str.html


4.8. 모듈을 수입하여, 그것을 편집하고 ( 같은 파이썬 프로세스 안으로) 다시 수입할 때, 변경한 것이 작용하지 않는 듯이 보입니다, 무엇 때문인가요?

효율성과 일관성의 이유 때문에, 파이썬은 오직 그 모듈 파일을 처음으로 수입할 때만 읽습니다. (그렇지 않으면 많은 모듈로 이루어진 프로그램, 각각이 같은 기본 모듈을 수입한다면, 그 기본 모듈을 읽고 또 읽을 것입니다.) 강제로 변경된 파일을 읽도록 하려면, 이렇게 하세요:

        import modname
        reload(modname)
경고: 이 테크닉은 100% 완전하게-증명된 것은 아닙니다. 특히, 다음과 같은 서술문을 담고 있는 모듈들은

        from modname import some_objects
그 수입된 객체들의 구형 버전과도 계속하여 잘 작동할 것입니다.


4.9. 어떻게 현재 모듈의 이름을 아나요?

모듈은 자신의 이름을 (미리 정의된) 전역 변수 __name__을 살펴봄으로써 알 수 있습니다. 만약 이것이 값 '__main__'을 가지면 여러분은 스크립트로서 실행하고 있는 것입니다.


4.10. 한 모듈이 스크립트로 실행될 때 어떤 여분의 코드를 실행하기를 원합니다. 내가 스크립트로 실행중인지 아닌지를 어떻게 압니까?

이전의 질문을 참조하세요. 예를 들어 만약 다음을 모듈의 마지막 라인에 놓는다면, main()은 모듈이 스크립트로 실행될 때만 호출됩니다:

        if __name__ == '__main__': main()


4.11. 데모 디렉토리부터 프로그램 하나를 실행하려고 하였지만 ImportError를 가지고 실패합니다: No module named ...; 무엇이 문제인가요?

이것은 아마도 (C로 씌여진) 선택적인 모듈이 시스템에 설정되지 않았기 때문일 것입니다. 특히 이것은 "Tkinter", "stdwin", "gl", "Xt" 또는 "Xm"과 같은 모듈들에 자주 일어납니다. Tkinter, STDWIN 과 다른 많은 모듈에 대해서는, Modules/Setup.in을 살펴보시면, 가능하기만 하다면, 이러한 모듈들을 파이썬에 추가하는 법에 대한 정보가 있습니다. 때로는 또 다른 패키지를 (예를 들어, Tkinter를 위해서는 Tcl와 Tk를) ftp로 먼저 내려받을 필요가 있을 것입니다. 때로는 그 모듈은 플랫폼 종속적으로만 작동합니다. (예를 들어, gl은 오직 SGI 머신에서만 작동합니다).

주의: 만약 불평이 "Tkinter" (대문자 T)에 관한 것이고 이미 "tkinter" (소문자 t) 모듈을 설정하였다면, 해결책은 tkinter를 Tkinter으로 혹은 그 반대로 이름을 바꾸지 않는 것입니다. 분명히 모듈 탐색 경로에 무엇인가 잘못이 있습니다. sys.path의 값을 점검해 보세요.

X-관련 모듈 (Xt와 Xm)에 대해서는, 더 많은 작업이 필요할 것입니다: 그 모듈들은 현재로 표준 파이썬 배포본에 포함되지 않습니다. ftp로 그 확장 tar 파일을 내려 받을 필요가 있습니다, 즉. 다음에서 ftp://ftp.python.org/pub/python/src/X-extension.tar.gz 내려받고 그리고 거기에 있는 지시사항을 따르세요.

다음 질문도 참조하세요.


4.12. STDWIN으로 성공적으로 파이썬을 구축하였습니다 그러나 어떤 모듈을 찾지 못합니다 (예를 들어. stdwinevents).

'stdwin'라는 이름의 라이브러리 디렉토리에는 하부디렉토리가 있는데 반드시 기본 모듈 탐색 경로에 있어야 합니다. Modules/Setup(.in)에는 이러한 목적을 위하여 사용가능하게 해야할 라인이 있습니다. -- 불행하게도 최근의 배포본에는 그 라인이 다른 STDWIN에-관련된 라인의 근처에 있지 않습니다 그래서 그것을 놓치기 쉽습니다.


4.13. 파이썬을 위해서는 어떤 GUI 도구들이 존재합니까?

어떤 플랫폼을 목적으로 하느냐에 따라서, 여러가지가 있습니다.

현재 지원되는 해결책들은:

크로스-플랫폼(Cross-platform):

Tcl/Tk 위젯 모둠에 대한 산뜻한 객체-지향 인터페이스가 있는데, Tkinter라고 부릅니다. 이것은 표준 파이썬 배포본의 일부로서 잘-지원되고 있습니다 -- 여러분이 해야할 필요가 있는 모든 것은 Tcl/Tk를 구축하고 설치하고 그리고 파이썬을 구축할 때 _tkinter 모듈과 Modules/Setup에 있는 TKPATH 정의를 사용가능하게 하는 것입니다. 이것이 아마도 설치하고 사용하기에 가장 쉬우며 가장 완벽한 위젯 모둠일 것입니다. 아마도 미래에 표준 파이썬 구이 API가 기본으로 하거나 적어도 Tkinter 인터페이스와 대단히 비슷하게 될 것입니다. Tk에 관하여, 소스에 대한 포인터를 포함하여, 더 많은 정보가 필요하시면, http://www.scriptics.com/에 있는 Tcl/Tk 홈페이지를 참조하세요. Tcl/Tk은 이제 Mac과 윈도우 플랫폼 (NT와 95에만)에 대하여 완전한 이식성이 있습니다; 필요한 것은 파이썬 1.4beta3 이상 그리고 Tk 4.1patch1 이상이 필요합니다.

wxPython이라고 불리우는 wxWindows에 대한 인터페이스가 있습니다. wxWindows는 C++으로 작성된 이식성 있는 구이 클래스 라이브러리입니다. GTK, Motif, MS-Windows 그리고 Mac을 목표로 지원합니다. 다른 플랫폼에 대한 이식은 고려되고 있거나 이미 약간의 작업이 이루어지고 있습니다. wxWindows는 그래픽 도구모음에 잠재하는 시각느낌을 그대로 보존합니다, 그리고 대단히 풍부한 위젯 모둠과 GDI 클래스 모둠이 있습니다. 더 많은 정보를 위해서는 http://www.wxwindows.org// wxWindows 페이지를 참조하세요. wxPython는 파이썬 확장 모듈로서 많은 wxWindows C++ 클래스들을 포장해주며, 그리고 파이썬 개발자들 사이에 빠르게 인기를 얻고 있습니다. wxPython을 소스의 형태로 혹은 wxWindows의 CVS 배포본으로, 또는 직접 http://alldunn.com/wxPython/ 홈페이지에서 얻을 수 있습니다.

제임스 헨스트리지(James Henstridge)에 의한 Gnome과 GIMP 도구 모음에 대한 엮기가 존재합니다; 다음을 참조하세요 ftp://ftp.daa.com.au/pub/james/python/.

KDE 엮기를 위해서는, ftp://ftp.kde.org/pub/kde/devel/kde-bindings을 참조하시거나 또는 http://www.river-bank.demon.co.uk/software/를 참조하세요.

OpenGL 엮기를 위해서는, http://starship.python.net/~da/PyOpenGL를 참조하세요.

플랫폼 종속적:

맥에 대한 이식은 본래의 맥 도구상자 호출을 지원하고 있는 모듈의 모음이 풍부하며 계속해서-커지고 있습니다. 다음을 참조하세요 ftp://ftp.python.org/pub/python/mac. 잭 얀센(Jack Jansen) jack@cwi.nl이 지원합니다.

마크 해몬드(Mark Hammond)에 의한 파이썬윈 (MHammond@skippinet.com.au)에는 마이크로소프트 기초 클래스(Microsoft Foundation Classes)에 대한 인터페이스와 파이썬 프로그래밍 환경이 포함되어 있는데 거의 대부분 파이썬으로 작성되었습니다. 다음을 참조하세요 http://www.python.org/windows/.

마이크로 소프트 기초 클래스 모델(MFC)에 토대를 두는 객체-지향 구이도 있는데, WPY라고 부르며, 짐 알스트롬(Jim Ahlstrom)jim@interet.com이 지원합니다. WPY로 작성된 프로그램은 변경없이 고유의 시각느낌을 가지고 (win32s를 사용하여) 윈도우 NT/95, 윈도우 3.1, 그리고 유닉스에서 (Tk를 사용하여) 실행됩니다. 윈도우와 리눅스를 위한 소스와 이진 파일들은 ftp://ftp.python.org/pub/python/wpy/에서 얻을 수 있습니다.

폐기되거나 혹은 소수의 해결책:

X11에 대한 인터페이스도 있는데, 아데나(Athena)와 모티프(Motif) 위젯 모둠을 포함하며 (모자이크의 HTML 위젯과 SGI의 GL 위젯과 같은, 약간의 개인적인 위젯들) 다음의 ftp://ftp.python.org/pub/python/src/X-extension.tar.gz에서 얻을 수 있습니다. 셔드 멀렌터(Sjoerd Mullender)sjoerd@cwi.nl가 지원하고 있습니다.

X11 인터페이스 위에 펄 스필링(Per Spilling)에 의한 vpApp 도구모음이 있는데, 이제는 셔드 멀렌더(Sjoerd Mullender)sjoerd@cwi.nl가 유지하고 있습니다. 다음 ftp://ftp.cwi.nl/pub/sjoerd/vpApp.tar.gz을 참조하세요.

SGI IRIX 만을 위해서라면, 지원되지 않고 있는 완벽한 GL과 FORMS에 대한 인터페이스가 있습니다. (GL : 그래픽 라이브러리 -- 저 수준이지만 대단히 훌륭한 3D 능력을 가집니다) (FORMS : 마크 오버마스(Mark Overmars)에 의하여 GL위에 구축된 버튼-과-슬라이더-등등의 패키지로서 -- 다음의 ftp://ftp.cs.ruu.nl/pub/SGI/FORMS/로부터 내려 받을 수 있습니다). 이것 역시 아마도 폐기되어 가고 있는 중일 것입니다, 이제는 OpenGL이 넘겨 받았습니다 (위를 참조하세요).

STDWIN에 대한 인터페이스가 있는데, Mac과 X11을 위한 플랫폼 독립적인 저-수준 윈도우 인터페이스 입니다. 이것은 완전하게 지원되지 않고 있으며, 빠르게 폐기되어 가고 있는 중입니다. STDWIN 소스는 다음 ftp://ftp.cwi.nl/pub/stdwin/에 있습니다.

WAFE에 대한 인터페이스가 있는데, X11 모티프와 아데나 위젯 모둠에 대한 Tcl 인터페이스입니다. WAFE는 다음 http://www.wu-wien.ac.at/wafe/wafe.html에 있습니다.


4.14. 파이썬에 데이타 베이스 패키지에 대한 인터페이스가 있나요?

네! 자세한 사항은, 데이타베이스 주제 지도서 (Database Topic Guide) http://www.python.org/topics/database/를 참조하세요.


4.15. 파이썬으로 복잡한 한-줄짜리 코드를 작성할 수 있나요?

그렇습니다. 다음의 예제 세개를 보세요, 울프 바텔트(Ulf Bartelt)의 배려:

        # Primes < 1000
        print filter(None,map(lambda y:y*reduce(lambda x,y:x*y!=0,
        map(lambda x,y=y:y%x,range(2,int(pow(y,0.5)+1))),1),range(2,1000)))
        # First 10 Fibonacci numbers
        print map(lambda x,f=lambda x,f:(x<=1) or (f(x-1,f)+f(x-2,f)): f(x,f)
,
        range(10))
        # Mandelbrot set
        print (lambda Ru,Ro,Iu,Io,IM,Sx,Sy:reduce(lambda x,y:x+y,map(lambda y,
        Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,Sy=Sy,L=lambda yc,Iu=Iu,Io=Io,Ru=Ru,Ro=Ro,i=IM,
        Sx=Sx,Sy=Sy:reduce(lambda x,y:x+y,map(lambda x,xc=Ru,yc=yc,Ru=Ru,Ro=Ro,
        i=i,Sx=Sx,F=lambda xc,yc,x,y,k,f=lambda xc,yc,x,y,k,f:(k<=0)or (x*x+y
*y
        >=4.0) or 1+f(xc,yc,x*x-y*y+xc,2.0*x*y+yc,k-1,f):f(xc,yc,x,y,k,f):chr
(
        64+F(Ru+x*(Ro-Ru)/Sx,yc,0,0,i)),range(Sx))):L(Iu+y*(Io-Iu)/Sy),range(Sy
        ))))(-2.1, 0.7, -1.2, 1.2, 30, 80, 24)
        #    \___ ___/  \___ ___/  |   |   |__ lines on screen
        #        V          V      |   |______ columns on screen
        #        |          |      |__________ maximum of "iterations"
        #        |          |_________________ range on y axis
        #        |____________________________ range on x axis
이것을 쉽게 시도해 보지는 마세요, 여러분!


4.16. C의 "?:" 삼진 연산자와 같은 것이 있나요?

직접적으로는 없습니다. 많은 경우에 a?b:c를 "a and b or c"로 흉내 낼 수 있습니다, 그러나 결점이 있습니다: 만약 b가 0이면 (또는 비어 있거나, 혹은 None 이라면 -- 테스트가 실패하는 어떤 것이라면) 그러면 c 가 대신에 선택될 것입니다. 이러한 일이 일어날 수 없는 코드를 살펴보면, 많은 경우에 증명할 수 있습니다 (즉. b는 상수이거나 절대로 거짓이 될 수 없는 형을 가지기 때문입니다), 그러나 일반적으로 이것은 문제가 될 수 있습니다.

팀 피터스(Tim Peters)가 다음의 해결책을 제시하였습니다: (a and [b] or [c])[0]. [b]는 싱글턴(한개의 요소를 가지는) 리스트이므로 절대로 거짓이 아닙니다, 그래서 잘못된 경로는 절대로 선택되지 않습니다; 그러면 [0]를 전체에 적용하면 실제로 원하는 b 또는 c 를 획득합니다. 그렇지만, 안타깝게도 'if'를 사용하여 코드를 재작성하는 것이 진짜로 불편하게 되는 희귀한 상황을 맞게 됩니다.


4.17. 클래스에 __del__을 정의했지만 그 객체를 삭제할 때 호출되지 않습니다.

이것에는 여러가지 이유가 가능합니다.

del 서술문은 필수적으로 __del__을 호출하지는 않습니다 -- 그저 그 객체의 참조 횟수를 감소시킬 뿐입니다, 그리고 만약 그 횟수가 0에 도달하면 __del__이 호출됩니다.

만약 데이타 구조가 순환 연결을 포함하고 있다면 (예를 들어. 각 자손이 하나의 부모 포인터를 가지고 있고 각 부모는 자손 목록을 가지고 있는 트리 구조의 경우라면) 그 참조 횟수는 절대로 0으로 되돌아 가지 않을 것입니다. 명시적으로 close() 메쏘드를 정의하여 그러한 포인터들을 제거해야만 할 것입니다. 제발 __del__을 직접적으로 호출하지 마세요 -- __del__은 close()를 호출해야만 하고 close()는 자신이 같은 객체에 대하여 한 번 이상 호출될 수 있도록 확인하여야만 합니다.

만약 그 객체가 except 절에서 표현식을 나포하는 함수에 대한 지역 변수였다면 (혹은 인수라면, 이것은 실제적으로 같은 것입니다), 가능성은 그 객체에 대한 참조가 스택 추적에서 담겨 있는 그대로 여전히 그 함수의 스택 프레임에 존재하는 것입니다. 보통, (더 좋은 것은: None을 할당하는 것) sys.exc_traceback 을 삭제하면 이것을 해결해 줄 것입니다. 만약 상호대화적인 인터프리터 상태에서 처리되지 않은 예외에 대하여 스택이 출력되면, 대신에 sys.last_traceback을 지우세요.

인터프리터가 종료할 때 모든 객체를 삭제하는 코드가 있지만, 파이썬이 쓰레드를 지원하도록 환경설정되어 있다면 호출되지 않습니다 (왜냐하면 다른 쓰레드들이 여전히 살아있을지도 모르기 때문입니다). 자신만의 청소 함수를 sys.exitfunc를 사용하여 작성할 수 있습니다 (질문 4.4 참조).

마지막으로, __del__ 메쏘드가 예외를 일으키면, 경고 메시지가 sys.stderr에 출력됩니다.

파이썬 2.0부터는, 쓰레기 수집기는 많은 순환고리가 외부 참조없이 사용한 공간을 재요구할 수 있습니다. 그렇지만, 실패가 예상되는 병리적 사례가 존재할 가능성이 있습니다, 그래서 여러분의 프로그램이 그러한 순환고리를 깬다는 것을 확인하는 것이 항상 가장 안전합니다.

질문 6.14의 목적은 새로운 쓰레기 수집 알고리즘을 설명하는 것입니다.


4.18. os.popen() 또는 os.system()을 사용하여 호출되는 프로그램들을 위한 쉘 환경을 어떻게 변경하나요? os.environ을 변경하는 것이 작동하지 않아요.

틀림없이 파이썬 1.4 이전 버전을 사용하고 있거나 putenv() 라이브러리 함수를 가지고 있지 않은 (아주 희귀한) 시스템을 사용하고 있습니다.

파이썬 1.4 이전에서는, 하부쉘로 건네지는 환경을 변경하는 것이 그 인터프리터에서는 생략되었습니다. 그렇게 하기위한 잘-구축된 이식 방법이 없다고 판단 되었기 때문입니다 (특히, 어떤 시스템은, putenv()를 가지고, 다른 시스템들은 setenv()를 가지며, 그리고 어떤 시스템들은 전혀 가지지 않습니다). 파이썬 1.4 현재부로, 거의 모든 유닉스 시스템은 putenv()를 가지고 있습니다 그리고 Win32 API도 가지고 있고, 그런식으로 os 모듈은 변경되어 os.environ에 대한 변경은 나포되고 그 상응하는 putenv() 호출이 이루어집니다.


4.19. 클래스가 무엇인가요?

클래스란 특별한 객체 형으로서 class 서술문을 실행하면 만들어집니다. 클래스 객체는 임시원형(템플리트)로 사용되어, 클래스 실체 객체를 만드는데, 그것은 데이타 구조와 데이타 형에 종속적인 프로그램 루틴 모두를 구체화합니다.


4.20. 메쏘드란 무엇인가요?

메쏘드는 함수로서 보통 어떤 객체 x에 대하여 x.name(arguments...)과 같이 호출합니다. 그 용어는 클래스와 클래스 실체의 메쏘드에도 사용되어지고 내장 객체의 메쏘드에도 사용됩니다. (후자는 완전하게 다른 구현을 가지며 파이썬 코드에서 호출 방식의 형태만을 공유합니다.) 클래스의 메쏘드 (그리고 클래스 실체의 메쏘드)는 class 정의안에서 함수로 정의됩니다.


4.21. self란 무엇입니까?

Self는 단순히 한 메쏘드의 첫 번째 인수에 대한 관례적인 이름일 뿐입니다 -- 즉. 클래스 정의 안에 정의된 함수입니다. meth(self, a, b, c)라고 정의된 메쏘드는 그 클래스의 실체 x에 대하여 x.meth(a, b, c)로 호출되어야만 합니다; 그 정의가 나타나는 클래스의 어떤 실체에 대해서, 그 호출된 메쏘드는 meth(x, a, b, c)로 호출된 것이라고 생각할 것입니다.


4.22. 엮여지지 않은 메쏘드란 무엇입니까?

엮여지지 않은 메쏘드란, 아직 실체에 엮여지지 않은 클래스에 정의된 메쏘드입니다. 클래스 속성을 요구하면 (클래스 속성은 함수가 될 수 있습니다), 엮여지지 않은 메쏘드를 얻습니다. 실체 속성을 요구하면 엮인 메쏘드를 획득합니다. 엮여진 메쏘드는 어떤 실체에 속하는지를 알고 있으며 그것을 호출하면 그 실체를 자동적으로 공급해 줍니다; 엮여지지 않은 메쏘드는 오직 그의 첫번째 인수로 어떤 클래스가 필요한지만을 알고 있을 뿐입니다 (파생된 클래스 역시 마찬가지입니다). 엮여지지 않은 메쏘드를 호출하면 그 문맥으로부터 첫 번째 인수를 "마법적으로" 파생시키지는 않습니다 -- 명시적으로 그것을 제공할 필요가 있습니다.

엮여지지 않은 메쏘드에 관한 약간의 주의사항: 특정한 객체의 엮여지지 않은 메쏘드를 참조할 때마다 엮여지지 않은 메쏘드 객체를 만들어 냅니다. 만약 다음과 같이 참조한다면 (a = inst.meth; b = inst.meth), 그들은 동등하기는 하지만 (a == b) 동일하지는 않을 것입니다 (a is not b).


4.23. 기본 클래스에 정의된 정의된 메쏘드를 그것을 덮어쓰는 파생클래스로부터 어떻게 호출하나요?

만약 클래스 정의가 "class Derived(Base): ..."로 시작한다면 Base 클래스 (혹은 Base의 기본 클래스)에 정의된 메쏘드를 Base.meth(self, arguments...)와 같이 호출할 수 있습니다. 여기에서, Base.meth는 엮여지지 않은 메쏘드입니다 (이전의 질문을 참조).


4.24. 기본 클래스로부터 메쏘드를 그 기본 클래스의 이름을 사용하지 않고 어떻게 호출하나요?

이렇게 하지 마세요. 진짜입니다. 진심으로 드리는 말씀입니다. 마치 self.__class__.__bases__[0].meth(self, arguments...)를 호출할 수 있는 듯이 보이지만, 이것은 이중으로-파생된 메쏘드가 여러분의 클래스로부터 파생될 때 실패합니다: 실체들에 대하여, self.__class__.__bases__[0]는 클래스이지, 그의 기본 클래스가 아닙니다 -- 그래서 (여러분이 Derived.meth안으로부터 이렇게 한다고 가정한다면) 재귀 호출을 시작할 것입니다.

이렇게 하기를 원할 때 가끔 여러분은 클래스들이 파이썬에서 제일 클래스라는 것을 잊어버립니다. 실체 수준 혹은 하부클래스 수준에서, 클래스를 지정하여 연산을 위임할 수 있습니다. 예를 들어 superclass의 "glorp" 연산을 사용하려면 정확한 superclass를 지적해서 사용할 수 있습니다.

  class subclass(superclass1, superclass2, superclass3):
      delegate_glorp = superclass2
      ...
      def glorp(self, arg1, arg2):
            ... subclass specific stuff ...
            self.delegate_glorp.glorp(self, arg1, arg2)
       ...
  class subsubclass(subclass):
       delegate_glorp = superclass3
       ...
그렇지만, 주의하세요. subsubclass에서 하부클래스화 하기 위해서 delegate_glorp를 설정하면 subclass.delegate_glorp에 대하여 무한 재귀를 야기할 것입니다. 주의 하세요! 아마도 자신만의 목적을 위해 너무 기분을 내고 있는지도 모릅니다. 디자인을 간결하게 하는 것을 고려해 보세요 (?).


4.25. 어떻게 나의 코드를 조직하여 기본 클래스를 더 쉽게 변경하도록 할 수 있나요?

그 기본 클래스에 대하여 별명을 정의할 수 있으며, 실제 기본 클래스를 클래스 정의 전에 거기에 할당하고, 그리고 그 별명을 전체 클래스에 걸쳐서 사용할 수 있습니다. 그러면 변경해야할 것은 오직 그 별명에 할당된 값입니다. 우연하게, 이 꼼수는 어떤 기본 클래스를 사용할지 (예를 들어, 자원의 사용가능성에 따라서) 동적으로 결정하기를 원할 때에도 유용합니다. 예를 들어:

        BaseAlias = <real base class>
        class Derived(BaseAlias):
                def meth(self):
                        BaseAlias.meth(self)
                        ...


4.26. 한 객체의 속성 혹은 메쏘드를 어떻게 알 수 있나요?

이것은 그 객체의 형에 따라 다릅니다.

사용자-정의 클래스의 실체 x에 대하여, 실체 속성은 사전 x.__dict__에서 발견할 수 있으며, 그리고 그의 클래스에 의해서 정의된 메쏘드와 속성들은 x.__class__.__bases__[i].__dict__에서 발견됩니다 (for i in range(len(x.__class__.__bases__))). 모든 클래스 메쏘드와 속성들을 찾으려면 기본 클래스들의 트리를 탐색할 필요가 있습니다.

다수이기는 하지만, 모든 내장 형들이 메쏘드 이름들을 x.__methods__에 정의하는 것은 아닙니다, 그리고 만약 데이타 속성들을 가지면, 그 이름들은 x.__members__에서 발견될 수 있습니다. 그렇지만 이것은 관례일 따름입니다.

정보가 더 필요하시면, 표준 (그러나 문서화되지 않은) 모듈 newdir의 소스를 읽어 보세요.


4.27. os.popen()으로 생성된 파이프에서 os.read()를 사용할 수 없는 것 같습니다.

os.read()는 저-수준 함수로서 파일 기술자를 취합니다 (작은 정수). os.popen()는 고-수준 파일 객체를 생성합니다 -- sys.std{in,out,err}에 사용되고 내장 open()함수에 의하여 반환되는 것과 같은 형입니다. 그리하여, os.popen()으로 생성된 파이프 p로부터 n 바이트를 읽으려면, p.read(n)을 사용할 필요가 있습니다.


4.28. 파이썬 스크립트를 어떻게 독립적인 이진 파일로 만들 수 있나요?

"Tools/freeze/"에 있는 "freeze" 도구가 원하는 바를 해 줍니다. README를 참조하세요.

이것은 다음과 같이 작동합니다. 소스를 재귀적으로 훓어서 수입 서술문들을 탐색하고 그리고 표준 파이썬 경로에 있는 모듈들과 (내장 모듈을 위한) 소스 디렉토리에 있는 모듈들을 찾습니다. 그리고나서 그것은 파이썬으로 작성된 모듈을 C 코드로 ( marshal 모듈을 사용하여 코드 객체로 변경될 수 있는 배열 초기화자로) "컴파일 합니다" 그리고 고객-맞춤 환경설정 파일을 만드는데 그 프로그램에서 실제적으로 사용되는 내장 함수들 만을 담고 있습니다. 그리고 나서 생성된 C 코드를 컴파일하고 그것을 파이썬 인터프리터의 나머지와 연결하여 스크립트와 정확하게 똑 같이 행동하는, 자신이-담겨진 이진 파일을 형성합니다.

힌트: freeze 프로그램은 스크립트이 파일이름이 ".py"로 끝날 때만 작동합니다.

윈도우에서 이렇게 하기를 원한다면, 두 개의 유틸리티가 도움이 될 것입니다. 첫째는 다음의 고든 맥밀란(Gordon McMillan)의 설치기 입니다.

    http://starship.python.net/crew/gmcm/install.html
그리고 둘 째는 다음의 토마스 헬러(Thomas Heller)의 py2exe입니다

    http://starship.python.net/crew/theller/py2exe/
후자의 도구는 여전히 개발중입니다, 그러나 이미 파이썬 COM 서버를 위해서 독립적인 .exe 파일을 만드는데 사용되어 왔습니다.


4.29. 파이썬을 위해서 어떤 WWW 도구들이 있나요?

라이브러리 참조 매뉴얼에 있는 다음 장 "인터넷 프로토콜과 지원(Internet Protocols and Support)"과 "인터넷 데이타 처리(Internet Data Handling)"라고 제목이 붙여진 장을 참조하세요. 파이썬은 서버-쪽과 클라이언트-쪽 웹 시스템을 구축하는데 도움을 주는 훌륭한 것들로 가득합니다.

파이썬의 웹 프레임워크에 관심이 있으시면, 다음의 훌륭한 사이트를 방문해 보세요

    http://groups.yahoo.com/group/python-web-modules.
파이썬으로 작성된 웹 브라우저도 있는데, Grail이라고 부릅니다 -- 다음 http://grail.cnri.reston.va.us/grail/을 참조하세요. 그렇지만, 최근 몇년동안에 이 코드가 얼마나 많이 유지 보수 되었는지는 모르겠습니다.


4.30. 입력과 출력 양쪽에 연결된 파이프로 어떻게 하부프로세스를 실행하나요?

표준 popen2 모듈을 사용하세요. 예를 들어:

	import popen2
	fromchild, tochild = popen2.popen2("command")
	tochild.write("input\n")
	tochild.flush()
	output = fromchild.readline()
경고: 일반적으로, 이렇게 하는 것은 현명하지 못합니다, 왜냐하면 쉽게 데드락을 야기할 수 있기 때문인데 여러분은 자손 프로세스로부터 출력을 기다리면서 정지하고 있는 동안에, 자손 프로세스는 여러분으로부터 입력을 기다리면서 정지하고 있게 됩니다. 이것은 자손 프로세스가 출력하는 것보다 더 많은 텍스트를 출력하기를 부모 프로세스가 예상하고 있기 때문에 야기될 수 도 있고, 또는 데이타가 강제 쓰기(flushing)가 결여되어, stdio 버퍼에 고착되어 있기 때문에 야기될 수도 있습니다. 물론 파이썬 부모 프로세스는 모든 어떤 출력이든지 읽기 전에 자손에게 보내는 데이타를 명시적으로 강제쓰기할 수 있습니다, 그러나 자손 프로세스가 원래 C 프로그램이라면, 강제쓰기는 보통 자동적이므로, 상호대화적일 지라도, 명시적으로 그 출력을 강제쓰기 하지 않도록 쉽게 작성되어질 수 있습니다

popen2에 있는 버그에 대한 주의사항: 여러분의 프로그램이 wait() 혹은 waitpid()를 호출하지 않는 한, 완결된 자손 프로세스는 절대로 제거되지 않습니다, 그리고 결국 popen2를 호출하는 것은 자손 프로세스의 개수 제한 때문에 실패할 것입니다. os.WNOHANG 선택사항을 가지고 os.waitpid를 호출하면 이것을 방지할 수 있습니다; 그러한 호출을 삽입하기 위한 최적 장소는 popen2를 다시 호출하기 전입니다.

많은 경우에, 여러분이 실제로 필요한 모든 것은 어떤 데이타를 명령어로 실행시켜서 그 결과를 돌려 받는 것입니다. 그 데이타의 크기가 무한 하지 않는한, 이렇게 하기 위한 가장 쉬운 (그리고 때로는 가장 효율적인!) 방법은 그것을 임시 파일에 써 넣고 그 임시 파일을 입력으로 해서 명령어를 실행하는 것입니다. 표준 모듈 tempfile은 함수 mktemp()를 수출하는데 유일한 임시 파일이름을 생성합니다.

주의할 것은 많은 상호대화적 프로그램들이 (예. vi) 표준 입력과 출력을 대신하는 파이프와 잘 작동하지 않습니다. 파이프 대신에 유사 ttys ("ptys")를 사용할 필요가 있을 것입니다. 라이브러리 모듈 pty.py에는 이러한 것을 사용하는 문서화되지 않은 코드가 있습니다 -- 안타깝게도 여기는 스스로 해결해야 하겠군요.

다른 해답은 돈 리브(Don Libe)의 "expect" 라이브러리에 대한 파이썬 인터페이스 입니다. expect와 접속시켜 주는 파이썬 확장은 "expy"라고 불리우며 다음 http://expectpy.sourceforge.net//에서 얻을 수 있습니다.

expect와 비슷하게 작동하는 순수한 파이썬적 해결책은 존 크로이(John Croix)에 의한 PIPE입니다. PIPE의 베타판은 다음 ftp://ftp.python.org/pub/python/contrib/System/에서 얻을 수 있습니다.


4.31. 터플 속에 인수들을 가진다면 어떻게 함수를 호출하나요?

내장 함수 apply()를 사용하세요. 예를 들어,

    func(1, 2, 3)
다음과 동일합니다.

    args = (1, 2, 3)
    apply(func, args)
이것은 func(args)와 같은 것이 아니라는 것을 주목하세요 -- 그것은 func()를 세개의 인수(정수 1,2 그리고 3) 대신에, 정확하게 하나의 인수(터플 args)로 호출합니다.

파이썬 2.0에서는, 확장된 호출 구문을 사용할 수도 있습니다:

f(*args)는 apply(f, args)와 동등합니다.


4.32. 이맥스에서 어떻게 파이썬을 위한 폰트-잠금-모드(font-lock-mode)를 사용가능하게 하나요?

이맥스 19.14 이상, 모든 XEmacs 20, FSF Emacs 19.34 혹은 모든 Emacs 20을 사용하고 계신다면, 최근의 python-mode.el을 사용하시면, 화면-잠금(font-lock)은 여러분을 대신하여 자동적으로 작동할 것입니다.

이전의 XEmacs 또는 Emacs를 사용하고 계시면 다음을 .emacs 파일에 삽입할 필요가 있을 것입니다:

        (defun my-python-mode-hook ()
          (setq font-lock-keywords python-font-lock-keywords)
          (font-lock-mode 1))
        (add-hook 'python-mode-hook 'my-python-mode-hook)


4.33. scanf() 또는 sscanf()와 같은 것이 있나요?

그러한 것은 없습니다.

간단한 입력 해석을 위해서는, 가장 간단한 접근법은 보통 그 라인을 공백으로-구분된 단어로 string.split()를 사용하여 나누구, 십진 문자열을 수치 값으로 string.atoi(), string.atol() 또는 string.atof()를 사용하여 변환하는 것입니다. (파이썬의 atoi()는 32-비트이고 atol()은 무한 정밀도입니다.) string.split는 선택적인 "sep" 매개변수를 제공하는데 그 라인이 공백이 아닌 다른 어떤 것으로 구분자를 사용하고자 할 때 유용합니다.

더 복잡한 입력 해석을 위해서는, 정규 표현식(re모듈 참조)이 C의 sscanf()보다 더 강력하고 적합합니다.

sscanf()를 흉내내는, 스티브 클리프트(Steve Clift)가 제공한 모듈이 있습니다; 다음 ftp 사이트의 contrib/Misc/sscanfmodule.c를 참조하세요:

    http://www.python.org/ftp/python/contrib-09-Dec-1999/Misc/


4.34. 입출력을 기다리면서 Tk 사건을 처리할 수 있나요?

네, 그리고 심지어는 쓰레드조차 필요하지 않습니다! 그러나 I/O 코드를 약간 수정할 필요가 있습니다. Tk는 Xt의 XtAddInput() 호출과 동등한데, 그것으로 역호출 함수를 등록할 수 있어서, I/O가 파일 기술자에 대하여 가능하게 될 때 Tk 주 회돌이로부터 호출될 것입니다. 여기에 여러분이 필요한 것이 있습니다:

        from Tkinter import tkinter
        tkinter.createfilehandler(file, mask, callback)
그 파일은 파이썬 파일 혹은 소켓 객체(실제로, fileno() 메쏘드를 가진 모든 것), 혹은 정수 파일 기술자일 수 있습니다. mask는 tkinter.READABLE 또는 tkinter.WRITABLE 상수중의 하나입니다. 역호출은 다음과 같이 호출됩니다:

        callback(file, mask)
작업이 끝나면, 다음을 사용하여 반드시 그 역호출 함수를 등록 취소해야 합니다.

        tkinter.deletefilehandler(file)
주의: 읽기를 위해 *얼마나 많은 바이트가* 사용가능한지를 알 수 없으므로, 파이썬 파일 객체의 read 또는 readline 메쏘드를 사용할 수 없는데, 왜냐하면 이것들은 계속하여 미리 정의된 개수의 바이트를 읽으려고 시도하기 때문입니다. 소켓에 대해서, recv() 혹은 recvfrom() 메쏘드는 잘 작동할 것입니다; 다른 파일들에 대해서는, os.read(file.fileno(), maxbytecount)를 사용하세요.


4.35. 출력 매개변수를 가진 함수를 어떻게 작성하나요 (참조에 의한 호출)?

[Mark Lutz] 기억해야 할 것은, 파이썬에서는 할당으로 인수들이 건네진다는 것입니다. 할당은 단순히 객체들에 대한 참조점만을 생성하기 때문에, 호출자와 피호출자 사이의 인수 이름 사이에 별명은 없습니다, 그래서 본래 참조에-의한-호출은 없습니다. 그러나 다양한 방법으로 흉내낼 수 있습니다:

1) 전역 변수를 사용함으로써; 그러나 아마도 그래서는 안되겠지요 :-)

2) 변경가능(적절한 곳에서 변경가능)한 객체를 건네 줌으로써:

      def func1(a):
          a[0] = 'new-value'     # 'a' references a mutable list
          a[1] = a[1] + 1        # changes a shared object
      args = ['old-value', 99]
      func1(args)
      print args[0], args[1]     # output: new-value 100
3) 인수들의 마지막 값을 유지하고, 터플을 반환함으로써:

      def func2(a, b):
          a = 'new-value'        # a and b are local names
          b = b + 1              # assigned to new objects
          return a, b            # return new values
      x, y = 'old-value', 99
      x, y = func2(x, y)
      print x, y                 # output: new-value 100
4) 그리고 파이썬의 객체 모델으로부터 파생된 다른 아이디어. 예를 들어, 변경가능한 사전에 건네주는 것이 더 명료할 수도 있습니다:

      def func3(args):
          args['a'] = 'new-value'     # args is a mutable dictionary
          args['b'] = args['b'] + 1   # change it in-place
      args = {'a':' old-value', 'b': 99}
      func3(args)
      print args['a'], args['b']
5) 또는 클래스 실체에 값들을 함께 싸-넣어서:

      class callByRef:
          def __init__(self, **args):
              for (key, value) in args.items():
                  setattr(self, key, value)
      def func4(args):
          args.a = 'new-value'        # args is a mutable callByRef
          args.b = args.b + 1         # change object in-place
      args = callByRef(a='old-value', b=99)
      func4(args)
      print args.a, args.b
   그러나 이것을 복잡하게 해야할 어떤 정당한 이유도 없습니다 :-).
[파이썬의 저자는 세번째 해결책을 대부분의 경우에 선호합니다.]


4.36. 파이썬에서의 지역과 전역 변수에 관한 규칙을 설명 좀 해 주세요.

[켄 만하이머(Ken Manheimer)] 파이썬에서, 프로시져 변수들은 묵시적으로 전역적입니다, 블록안의 어떤 곳에서 할당되지만 않는다면 말이지요. 그러한 경우에 그 변수들은 묵시적으로 지역적입니다, 그리고 명시적으로 그것들을 '전역(global)'으로 선언할 필요가 있습니다.

처음에는 약간 놀라겠지만, 잠시 생각해 보면 이해가 됩니다. 한 편으로는, 할당된 변수들에 대해 'global'을 요구함으로써 의도하지 않은 부-작용으로부터 방어막을 제공합니다. 다른 한편으로, 만약 global이 모든 전역 참조에 대하여 필요하다면, 항상 global을 사용하는 편이 좋을 것입니다. 예를 들어, 내장 함수 혹은 수입된 모듈의 컴포넌트에 대한 모든 참조점들을 global로 선언할 필요가 있습니다. 이러한 혼란때문에 부-작용을 구별해 내는 '전역'선언의 유용함이 빛을 잃어 버릴 것입니다.


4.37. 서로간에 수입을 하는 모듈을 어떻게 가질 수 있나요?

짐 로스킨트(Jim Roskind)는 다음의 순서를 각 모듈에 권장합니다:

먼저: 모든 수출문 (전역 변수, 함수, 그리고 클래스와 같은, 수입된 기본 클래스를 필요로 하지 않는 것들).

그리고 나서: 모든 수입 서술문.

마지막으로: 모든 작동 코드 (수입된 값으로부터 초기화된 전역 변수들을 포함한다).

수입문들이 이상한 곳에 나타나기 때문에 파이썬의 저자는 이러한 접근법을 별로 좋아하지 않습니다, 그러나 그것이 작동한다는 것은 인정해야 합니다. 그가 권장한 전략은 모든 "from <module> import *"의 사용을 피하고 (그래서 수입된 모듈의 모든 것은 <module>.<name>으로 참조됩니다.) 그리고 모든 코드를 함수 안쪽에 배치히는 것입니다. 전역 변수와 클래스 변수를 초기화 하려면 상수 혹은 내장 함수만을 사용해야 합니다.


4.38. 파이썬에서 객체를 어떻게 복사하나요?

총괄적인 복사 연산이 파이썬으로 구축되어 들어가지는 않았습니다, 그렇지만 대부분의 객체 형은 복제물을 생성하는 방법을 가지고 있습니다. 대단히 일반적인 객체들을 위한 방법을 소개하면:

변경불가 객체(숫자, 문자열, 터플)에 대해서는, 복제가 불필요한데 그들의 값이 변경이 불가능하기 때문입니다. 리스트 (그리고 일반적으로 변경가능한 연속열 형들)에 대해서는, 복제는 표현식 l[:]에 의해서 생성됩니다. 사전을 위해서는, 다음의 함수가 복제물을 반환합니다:

        def dictclone(o):
            n = {}
            for k in o.keys(): n[k] = o[k]
            return n
마지막으로, 일반적인 객체에 대해서는, "copy" 모듈은 객체를 복사하기 위해 두 개의 함수를 정의합니다. copy.copy(x)는 위에 언급한 규칙에 의하여 보여진대로 복사본을 반환합니다. copy.deepcopy(x)는 복합적인 객체의 요소들도 복사합니다. 라이브러리 참조 매뉴얼에 있는 이 모듈에 관한 섹션을 살펴보세요.


4.39. 파이썬에 불멸하는 객체를 구현하는 법? (Persistent == 자동적으로 디스크에 저장되고 복구되는.)

라이브러리 모듈 "pickle"은 이제 이 문제를 매우 일반적이 방법으로 해결합니다 (그렇지만 여전히, 열려진 파일, 소켓 혹은 윈도우와 같은 것들을 저장할 수는 없습니다), 그리고 라이브러리 모듈 "shelve"는 pickle과 (g)dbm을 사용하여 임의의 파이썬 객체를 담고 있는 불멸의 짝짓기를 생성합니다. 더 나은 성능을 원하시면 상대적으로 최근의 cPickle 모듈 최신 버전을 참고하세요.

약간은 어색한 처리 방법은 pickle의 귀여운 여동생, marshal을 사용하는 것입니다. marshal 모듈은 비순환적 기본 파이썬 형들을 파일과 문자열로, 그리고 그 반대로 저장하는 대단히 빠른 방법을 제공합니다. marshal이 실체들을 저장하거나 공유 참조점들을 적절하게 처리하는 작업등에는 부적절하기는 하지만, 그것은 엄청나게 빠르게 실행됩니다. 예를 들어 반 메가의 데이타를 적재하는데 (어떤 머신에서는) 3분의 1초 이하가 소요됩니다. 때로는 이것때문에 gdbm을 pickle/shelve와 사용하는 것과 같은 좀 더 복잡하고 일반적인 작업을 하는 것이 빛을 잃습니다.


4.40. __spam를 사용해 보려고 하는데 _SomeClassName__spam에 관한 에러를 맞이합니다.

두개의 이끄는 밑줄문자를 가진 변수들은 클래스 사적 변수들을 정의하기 위한, 간결한 그러나 효율적인 방법을 제공하기 위해 "만들어졌습니다". 파이썬 지침서의 "New in Release 1.4"장을 참조하세요.


4.41. 어떻게 파일을 삭제하나요? 그리고 다른 파일관련 질문들.

os.remove(filename) 혹은 os.unlink(filename)를 사용하세요; 문서를 원하시면, 그 라이브러리 매뉴얼에서 posix 섹션을 참조하세요. 그 둘은 같은 동일한 것입니다, unlink()는 이 함수를 위한 유닉스의 이름일 뿐입니다. 이전의 파이썬 버전에서는, os.unlink()만이 사용가능 했습니다.

디렉토리를 제거하기 위해서는, os.rmdir()을 사용하고; os.mkdir()을 사용해서 디렉토리를 만드세요.

파일의 이름을 바꾸려면, os.rename()을 사용하세요.

파일을 자르려면, 그것을 f = open(filename, "r+")을 사용하여 열고, 그리고 f.truncate(offset)을 사용하세요; offset은 현재의 탐색위치가 기본값입니다. ("r+" 모드는 그 파일을 읽기와 쓰기용으로 개방합니다.) os.open()으로 열려진 파일들에 대해서는 os.ftruncate(fd, offset)도 있습니다 -- 유닉스 전문가용.

shutil 모듈은 또한 파일들에 대한 작업을 하는 많은 수의 함수들을 담고 있는데 copyfile, copytree, 그리고 rmtree 등등을 포함합니다.


4.42. urllib 또는 httplib를 수정하여 HTTP/1.1를 지원하는 법?

최근 버전의 파이썬(2.0 이상)은 기본적으로 HTTP/1.1을 지원합니다.


4.43. compile() 또는 exec 중에 만나는 이해할 수 없는 구문 에러.

서술문 모둠이 (표현식과 대조하여) compile(), exec 또는 execfile()로 컴파일 될 때, 그것은 반드시 newline으로 끝나야만 합니다. 어떤 경우에, 소스가 들여쓰기된 블록으로 끝날때는, 적어도 두 개의 newlines이 필요한 듯이 보입니다.


4.44. 문자열을 어떻게 숫자로 바꾸나요?

정수에 대해서는, 내장 int() 함수를 사용하세요, 예. int('144') == 144. 비슷하게, long()은 문자열을 배정도 정수로 변환합니다, 예. long('144') == 144L; 그리고 float()는 부동소수점수로 변환합니다, 예. float('144') == 144.0.

주의할 것은 이러한 것들은 십진 번역으로 제한된다는 것입니다, 그래서 int('0144') == 144 그리고 int('0x144')는 ValueError를 일으킵니다. 파이썬 2.0에서 int는 변환하기 위해서 밑수(base)를 선택적인 두 번째 인수로 취하는데, 그래서 int('0x144', 16) == 324.

더욱 유연하게 사용하고 싶거나, 혹은 파이썬 1.5 이전이라면, string 모듈을 수입해서 정수에 대해서는 string.atoi() 함수를 사용하고, 배정도 정수에 대해서는 string.atol()를 사용하거나, 혹은 부동소수점수에 대해서는 string.atof()를 사용하세요. 예를 들어, string.atoi('100', 16) == string.atoi('0x100', 0) == 256. string 모듈에 관하여 더 자세히 알고 싶으면 라이브러리 참조 매뉴얼 섹션을 참조하세요.

그러한 모든 것들 대신에 내장 함수 eval()을 사용할 수는 있지만, 권장되지 않습니다, 왜냐하면 어떤이가 (디스크를 포맷하는 것과 같은) 원하지 않는 부작용을 가지는 파이썬 표현식을 넘겨줄 수 있기 때문입니다. 또한 숫자를 파이썬의 표현식으로 번역해버리는 효과도 가지는데, 예를 들어 eval('09')는 파이썬이 '0'으로 시작하는 숫자들을 8진수(base 8)로 간주하기 때문에 구문에러를 발생시킵니다.


4.45. 어떻게 숫자를 문자열로 변환하나요?

예를 들어, 숫자 144를 문자열 '144'로 변환하려면, 내장 함수 repr() 또는 backquote 표기법을 사용하세요 (이것들은 동등합니다). 만약 16진수 혹은 8진수 표현을 원하면, 각각에 대하여 내장 함수 hex() 또는 oct()를 사용하세요. 환상적으로 형식화하려면, 문자열에 % 연산자를 사용하세요, C의 printf 형식과 마찬가지로, 예를 들어, "%04d" % 144 는 '0144'를 산출하고 "%.3f" % (1/3.0)는 '0.333'을 산출합니다. 자세한 것은 라이브러리 참조 매뉴얼을 보세요.


4.46. 어떻게 파일을 복사하나요?

shutil 모듈이 있는데 복사 회돌이를 구현하는 copyfile() 함수를 담고 있습니다; 그렇지만, 매킨토시에는 충분하지 않습니다: 그것은 자원 포크 (resource fork)와 파인더 정보(Finder info)를 복사하지 않습니다.


4.47. 한 객체가 주어진 클래스의 실체인지 혹은 그의 하부 클래스인지를 어떻게 점검하나요?

그 클래스들을 대충대충 개발하고 있다면, 더욱 적절하게 객체-지향적인 스타일로 프로그램하는 편이 좋을 것입니다 -- 클래스 구성원에 기초한 다른 일을 하는 대신에, 메쏘드를 사용하고 그 메쏘드를 다른 클래스에 다르게 정의하는 것은 어떤가요?

그렇지만, 어떤 고정된 상황에서는 클래스 구성원을 테스트할 필요가 있습니다.

파이썬 1.5에서, 내장 함수 isinstance(obj, cls)를 사용할 수 있습니다.

다음의 접근법은 이전의 파이썬 버전과 사용될 수 있습니다:

불명확한 방식은 그 객체를 예외로 일으키고, 테스트 하기를 원하는 클래스로 그 예외를 나포하는 것입니다:

	def is_instance_of(the_instance, the_class):
	    try:
		raise the_instance
	    except the_class:
		return 1
	    except:
		return 0
이 테크닉은 "subclassness"를 클래스의 모음과 구별하는 데에 역시 사용될 수 있습니다.

                try:
                              raise the_instance
                except Audible:
                              the_instance.play(largo)
                except Visual:
                              the_instance.display(gaudy)
                except Olfactory:
                              sniff(the_instance)
                except:
                              raise ValueError, "dunno what to do with this!"
이것은 예외 나포가 클래스 혹은 하부클래스 구성원을 테스트한다는 사실을 이용합니다.

다른 접근법은 주어진 클래스에 대하여 아마도 유일한 클래스 속성의 존재를 테스트하는 것입니다. 예를 들어:

	class MyClass:
	    ThisIsMyClass = 1
	    ...
	def is_a_MyClass(the_instance):
	    return hasattr(the_instance, 'ThisIsMyClass')
이 버전은 라인내장(inline)하기가 더 쉬우며, 더욱 빠를 것입니다 (라인내장되면(inlined) 확실히 더 빠릅니다). 단점은 다른 어떤 사람이 다음과 같이 속일 수가 있다는 것입니다:

	class IntruderClass:
	    ThisIsMyClass = 1    # Masquerade as MyClass
	    ...
그러나 이것은 하나의 사양으로서 간주될 수 있습니다 (어쨋든, 파이썬에는 속일 수 있는 수 많은 다른 방법들이 있습니다). 또 다른 단점은 그 클래스가 구성원(membership) 테스트를 위해 미리 준비되어야 한다는 것입니다. 만약 그 클래스를 위해 "소스 코드를 제어하지 않는다면" 그 클래스를 변경하여 테스트가능하도록 지원하는 것은 권장할 수 없습니다.


4.48. 위임이란 무엇인가요?

위임(Delegation)이란 객체 지향 테크닉을 지칭하는 것으로서 파이썬 프로그래머들이 특별한 편의를 위해 구현합니다. 다음을 연구해 보세요:

  from string import upper
  class UpperOut:
        def __init__(self, outfile):
              self.__outfile = outfile
        def write(self, str):
              self.__outfile.write( upper(str) )
        def __getattr__(self, name):
              return getattr(self.__outfile, name)
여기에서 UpperOut 클래스는 write 메쏘드를 재정의하여 아래의 self.__outfile.write 메쏘드를 호출하기 전에 인수 문자열을 대문자로 변환합니다, 그러나 모든 다른 메쏘드들은 아래의 self.__outfile 객체에 위임됩니다. 위임(delegation)은 "마법의" __getattr__ 메쏘드로 달성됩니다. 이 메쏘드의 사용법에 관하여 더 많은 정보를 원하시면 언어 참조서를 보세요.

더욱 일반적인 경우에 대해서는 위임(delegation)은 꼼수적일 수 있습니다. 특히 속성을 설정하거나 획득해야만 할 때는, 그 클래스는 반드시 __settattr__ 메쏘드도 역시 정의해야 합니다, 그리고 대단히 주의깊게 그렇게 해야만 합니다.

__setattr__의 기본적인 구현은 다음과 대체적으로 동등합니다:

   class X:
        ...
        def __setattr__(self, name, value):
             self.__dict__[name] = value
        ...
대부분의 __setattr__ 구현은 self.__dict__를 변경하여 무한 재귀를 야기하지 않고서 self에 대한 지역 상태를 저장하여야 합니다.


4.49. 어떻게 파이썬 프로그램 혹은 컴포넌트를 테스트하나요.

우리가 예상하기로는 이 질문의 목적으로 여러분은 테스트 프레임워크 안에서 컴포넌트를 테스트 하는 것보다는, 독립적인 테스트에 관심을 가지고 있을 것입니다. 가장 훌륭하다고 알려진 테스트 프레임워크는 PyUnit 모듈이며, 다음에서 유지되고 있습니다.

    http://pyunit.sourceforge.net//
독립적인 테스트를 위해서는, 훌륭한 모듈 디자인을 사용하여, 쉽게 테스트 될 수 있도록, 프로그램을 작성하는 것이 도움이 됩니다. 특히 프로그램은 거의 모든 기능을 함수나 혹은 클래스 메쏘드에 캡슐화해야 합니다 -- 그리고 이것은 때로 그 프로그램을 더 빠르게 만드는 놀라운 그리고 기쁨 넘치는 효과를 가집니다. (왜냐하면 지역 변수는 전역 변수보다 더 빠르기 때문입니다). 게다가 프로그램은 변경되는 전역 변수에 의존하는 것을 피해야 합니다, 왜냐하면 이것은 테스트를 더욱 더 어렵게 하기 때문입니다.

프로그램의 "전역적 주 논리구성(global main logic)"은 다음과 같이 간결합니다.

  if __name__=="__main__":
       main_logic()
프로그램의 주 모듈이 최하위에 있습니다.

프로그램이 함수와 클래스 행위들의 가시적인 모임으로 조직되고 나면 그 행위들을 연습시켜 보는 테스트 함수를 작성하여야 합니다. 테스트 모둠은 일련의 테스트를 자동화하는 각 모듈과 결합될 수 있습니다. 이것은 엄청 많은 작업같이 들리지만, 파이썬은 간결하고 유연하므로 놀랍도록 쉽습니다. 테스트 함수를 "생산 코드(production code)"와 동시에 작성하게 되면 더욱 쉽고 재미있게 코딩할 수 있습니다, 왜냐하면 이렇게 하면 버그를 쉽게 발견할 수 있고 심지어는 디자인 결함을 조기에 발견할 수 있기 때문입니다.

프로그램의 주 모듈로 쓰이지 않을 "지원 모듈(Support modules)"은 그 모듈의 자체 테스트를 요청하는 "테스트 스크립트 번역(test script interpretation)"을 포함할 수 있습니다.

   if __name__ == "__main__":
      self_test()
심지어는 복잡한 외부 인터페이스와 작동하는 프로그램조차도, 그 외부 인터페이스가 사용불가능할 때, 파이썬으로 구현된 "모조" 인터페이스를 사용하여 테스트 될 수 있습니다, 다음 클래스는 (부분적인) "모조(fake)" 파일 인터페이스를 정의하고 있습니다:

 import string
 testdata = "just a random sequence of characters"
 class FakeInputFile:
   data = testdata
   position = 0
   closed = 0
   def read(self, n=None):
       self.testclosed()
       p = self.position
       if n is None:
          result= self.data[p:]
       else:
          result= self.data[p: p+n]
       self.position = p + len(result)
       return result
   def seek(self, n, m=0):
       self.testclosed()
       last = len(self.data)
       p = self.position
       if m==0:
          final=n
       elif m==1:
          final=n+p
       elif m==2:
          final=len(self.data)+n
       else:
          raise ValueError, "bad m"
       if final<0:
          raise IOError, "negative seek"
       self.position = final
   def isatty(self):
       return 0
   def tell(self):
       return self.position
   def close(self):
       self.closed = 1
   def testclosed(self):
       if self.closed:
          raise IOError, "file closed"
f=FakeInputFile()을 시도해 보고 그 연산을 테스트 해 보세요.


4.50. 다차원 리스트 (array)가 깨졌습니다! 어찌된 일인지요?

아마도 다차원 배열을 다음과 같은 방식으로 시도하신 것 같습니다.

   A = [[None] * 2] * 3
이것은 길이 2인 같은 리스트에 대한 세개의 참조점을 포함하는 리스트를 생성합니다. 한 줄에 대한 변경은 모든 줄에서 보여질 것입니다, 아마도 원하시는 바가 아닐 것입니다. 다음이 훨씬 더 잘 작동합니다:

   A = [None]*3
   for i in range(3):
        A[i] = [None] * 2
이것은 길이 2인 3 개의 서로 다른 리스트를 포함하는 리스트를 만들어 냅니다.

괴이하다고 느낀다면, 다음과 같은 방식으로 해 볼 수도 있습니다:

   w, h = 2, 3
   A = map(lambda i,w=w: [None] * w, range(h))
파이썬 2.0에서는 위의 라인은 리스트 번역을 사용하여 표기될 수도 있습니다:

   w,h = 2,3
   A = [ [None]*w for i in range(h) ]


4.51. 복잡한 정렬을 하려고 합니다: 슈바찌언 변형(Schwartzian Transform)을 파이썬에서 할 수 있습니까?

네, 그리고 파이썬에서 단 한번만 작성하시면 됩니다:

 def st(List, Metric):
     def pairing(element, M = Metric):
           return (M(element), element)
     paired = map(pairing, List)
     paired.sort()
     return map(stripit, paired)
 def stripit(pair):
     return pair[1]
이 테크닉은, 랜들 슈바르쯔(Randal Schwartz)의 덕분으로, 각 요소를 그의 "정렬 값(sort value)"에 짝지어주는 방식으로 리스트의 요소들을 정렬합니다. 예를 들어, 만약 L이 문자열을 담은 리스트라면

   import string
   Usorted = st(L, string.upper)
   def intfield(s):
         return string.atoi( string.strip(s[10:15] ) )
   Isorted = st(L, intfield)
Usorted는 L의 요소들을 마치 대문자인 것처럼 정렬하여 산출하고, 그리고 Isorted는 L의 요소들을 정수 값들에 의해서 정렬하여 산출하는데 그 정수값들은 위치 10에서 시작하여 위치 15를 마지막으로 썰어 놓은 문자열 조각에 나타납니다. 파이썬 2.0에서 이것은 리스트 번역으로 더 자연스럽게 달성될 수 있습니다:

  import string
  tmp1 = [ (string.upper(x),x) for x in L ] # Schwartzian transform
  tmp1.sort()
  Usorted = [ x[1] for x in tmp1 ]
  tmp2 = [ (int(s[10:15]), s) for s in L ] # Schwartzian transform
  tmp2.sort()
  Isorted = [ x[1] for x in tmp2 ]

주목할 것은 Isorted는 다음과 같이 계산될 수도 있습니다

   def Icmp(s1, s2):
         return cmp( intfield(s1), intfield(s2) )
   Isorted = L[:]
   Isorted.sort(Icmp)
그러나 이 메쏘드는 L의 각 요소들에 대하여 여러번 intfield를 계산하기 때문에, 슈바찌언 변형보다는 더 느립니다.


4.52. 터플과 리스트 사이를 변환하는 법?

함수 tuple(seq)는 임의의 연속열을 같은 순서의 같은 항목을 가지는 터플로 변환합니다. 예를 들어, tuple([1, 2, 3])은 (1, 2, 3) 을 산출하고 tuple('abc')는 ('a', 'b', 'c')를 산출합니다. 만약 그 인수가 터플이라면, 복사본을 만들지 않고 같은 객체를 반환합니다, 그래서 한 객체가 이미 터플인지 확신하지 못할 때는 tuple()을 호출하는 것이 안전합니다.

함수 list(seq)는 임의의 연속열을 같은 순서의 같은 항목을 가지는 리스트로 변환합니다. 예를 들어, list((1, 2, 3))은 [1, 2, 3]를 산출하고 list('abc')는 ['a', 'b', 'c']를 산출합니다. 만약 그 인수가 리스트라면, seq[:]와 마찬가지로 복사본을 만듭니다.


4.53. urllib으로 열어본 파일들에 이끄는 쓰레기가 포함되어 있습니다. 전자메일 머리부와 같이 보입니다.

엄청나게 오래된 파이썬 버전에서는 HTTP/1.1을 지원하지 않는 라이브러리를 제공했습니다; 파이썬 1.4에 있는 바닐라( vanilla) httplib는 오로지 HTTP/1.0만을 인식합니다. 파이썬 2.0에서 완전한 HTTP/1.1 지원이 포함되었습니다.


4.54. 주어진 클래스에서 모든 실체들의 목록을 어떻게 얻나요?

파이썬은 한 클래스의 (혹은 내장 형의) 모든 실체들을 추적하지 않습니다.

그 클래스의 구성자를 프로그램하여 모든 실체들을 추적하도록 할 수 있습니다, 그러나 여러분이 대단히 똑똑하지 않다면, 이것의 단점은 그 실체들이 절대로 삭제되지 않는다는 것인데, 모든 실체들을 담은 리스트가 그 실체들의 참조를 유지하고 있기 때문입니다.

(이 꼼수는 확보하고 있는 실체들의 참조 횟수를 정기적으로 들여다 보는 것인데, 만약 참조 횟수가 일정 수준 이하라면, 그것을 리스트로부터 제거합니다. 그 수준을 결정하는 것은 꼼수적입니다 -- 분명히 1 보다는 크겠지요.)


4.55. 정규 표현식이 regex.error로 실패합니다: 일치 실패(match failure).

이것은 보통 너무 많은 역추적으로 인하여 야기됩니다; 정규 표현식 엔진은 고정된 크기의 스택을 가지며 기껏해야 4000 개의 역추적 점을 보유할 뿐입니다. 예를들어 ".*"에 의해서 일치되는 각각의 모든 문자들은 역추적 점을 나타냅니다, 그래서 다음과 같이 간단한 탐색조차도

  regex.match('.*x',"x"*5000)
실패할 것입니다.

이것은 파이썬 1.5에 도입된 re 모듈에서 고쳐졌습니다; 더 정보를 원하시면 re에 관한 라이브러리 참조 섹션을 참고하세요.


4.56. 신호 처리자를 작동시킬 수 없습니다.

가장 흔한 문제는 그 신호 처리자가 잘못된 인수 리스트로 선언되었다는 것입니다. 그것은 다음과 같이 호출됩니다

	handler(signum, frame)
그래서 이것은 두 개의 인수로 선언되어야 합니다:

	def handler(signum, frame):
		...


4.57. 함수에서 전역 변수를 사용할 수 없습니다? 도와주세요!

다음과 같이 하셨나요?

   x = 1 # make a global
   def f():
         print x # try to print the global
         ...
         for j in range(100):
              if q>3:
                 x=4
함수안에 할당된 어떤 변수도 특별하게 전역으로 선언되지 않는 한 그 함수에 대하여 지역적입니다. 하나의 값이 그 함수 몸체의 마지막 서술문으로 x 에 엮여 있으므로, 컴파일러는 x 가 지역적이라고 간주합니다. 결과적으로 "print x"는 초기화 되지 않은 지역 변수를 출력하려고 시도하고 NameError를 촉발시킬 것입니다.

그러한 경우에 해결책은 명시적인 전역 선언을 그 함수의 처음에 삽입하는 것입니다, 그것을 만들어 보면

   def f():
         global x
         print x # try to print the global
         ...
         for j in range(100):
              if q>3:
                 x=4

이 경우에, x 에 대한 모든 참조점은 모듈 이름공간에서 온 x 에 대한 참조점으로 이해됩니다.


4.58. 음의 지표란 무엇인가요? 왜 list.insert()는 그것을 사용하지 않나요?

파이썬의 연속열은 양수와 음수로 지표화됩니다. 양수에 대해서는 0은 첫 번째 지표이고 1 은 두 번째 지표이고 등등 입니다. 음수에 대해서는 -1이 가장 마지막 지표이고 -2는 완성직전 (마지막 바로 전) 지표이다 등등입니다. seq[-n]를 seq[len(seq)-n]와 동일하게 생각하세요.

음수 지표를 사용하면 대단히 편리할 수 있습니다. 예를 들어 문자열 Line이 newline으로 끝나면 Line[:-1]은 그 newline을 뺀 Line의 모든 것입니다.

슬프게도 리스트 내장 메쏘드 L.insert는 음의 지표를 준수하지 않습니다. 이 사양은 실수라고 생각되어질 수도 있겠지만 실존하는 프로그램들이 이 사양에 의존하고 있으므로 오랫동안 유지될 것 같습니다. 음수 지표에 대한 L.insert는 그 리스트의 시작부에 삽입합니다. "적절한" 음의 지표 행위를 얻으려면 그 insert 메쏘드 대신에 L[n:n] = [x]을 사용하세요.


4.59. 어떻게 하나의 리스트를 다른 리스트로부터 값으로 정렬할 수 있나요?

터플을 담은 리스트를 정렬할 수 있습니다.

  >>> list1 = ["what", "I'm", "sorting", "by"]
  >>> list2 = ["something", "else", "to", "sort"]
  >>> pairs = map(None, list1, list2)
  >>> pairs
  [('what', 'something'), ("I'm", 'else'), ('sorting', 'to'), ('by', 'sort')]
  >>> pairs.sort()
  >>> pairs
  [("I'm", 'else'), ('by', 'sort'), ('sorting', 'to'), ('what', 'something')]
  >>> result = pairs[:]
  >>> for i in xrange(len(result)): result[i] = result[i][1]
  ...
  >>> result
  ['else', 'sort', 'to', 'something']
그리고 문제를 이해 못하겠다면, 위의 예제를 보세요;c). "I'm"이 "by" 앞에 정렬된다는 것을 주목하세요. 왜냐하면 아스키 순서로 대문자 "I"는 소문자 "b"의 앞에 오기 때문입니다. 질문 4.51도 참조하세요.

파이썬 2.0에서 이것은 다음과 같이 작성될 수 있습니다:

 >>> list1 = ["what", "I'm", "sorting", "by"]
 >>> list2 = ["something", "else", "to", "sort"]
 >>> pairs = zip(list1, list2)
 >>> pairs
 [('what', 'something'), ("I'm", 'else'), ('sorting', 'to'), ('by', 'sort')]
 >>> pairs.sort()
 >>> result = [ x[1] for x in pairs ]
 >>> result
 ['else', 'sort', 'to', 'something']
[Followup]

어떤 사람이 물었습니다, 마지막 단계에 대해서는 이건 어때요:

  result = []
  for p in pairs: result.append(p[1])
이것이 훨씬 더 읽기 쉽습니다. 그렇지만, 간단하게 테스트해 본 바에 의하면 기다란 리스트에 대해서는 거의 두 배나 느리다는 것을 알수 있습니다. 왜일까요? 무엇보다도, append() 연산은 메모리를 재할당해야만 합니다, 약간의 꼼수를 사용해서 매번 그렇게 하는 것을 피하기는 하지만, 여전히 가끔은 그렇게 해야만 합니다, 그리고 분명히 그것때문에 많은 대가를 치릅니다. 두번째로, 표현식 "result.append"는 여분의 속성 참조를 필요로 합니다. 속성 참조는 다음과 같이 재작성하게되면 제거될 수 있습니다:

  result = []
  append = result.append
  for p in pairs: append(p[1])
이것은 잃어버린 속도를 약간 되찾아 주기는 하지만, 원래의 해결책 보다는 여전히 상당히 느리며, 전혀 덜 복잡하지도 않습니다.


4.60. 왜 dir()이 파일과 리스트 같은 내장 형에 대하여 작동하지 않나요?

그것은 파이썬 1.5에서부터 시작하였습니다.

1.4를 사용하시면, 주어진 객체가 어떤 메쏘드를 지원하는 지를 __methods__ 속성을 살펴봄으로써 알 수 있습니다:

    >>> List = []
    >>> List.__methods__
    ['append', 'count', 'index', 'insert', 'remove', 'reverse', 'sort']


4.61. 어떻게 CGI 폼 제출을 흉내낼 수 있나요 (METHOD=POST)?

폼을 제출(POSTing)한 결과로 나온 웹 페이지를 열람하고 싶습니다. 이것을 쉽게 할 수 있도록 해주는 코드가 존재하나요?

네, 여기에 httplib를 사용하는 간단한 예제가 있습니다.

#!/usr/local/bin/python
import httplib, sys, time
### build the query string
    qs = "First=Josephine&MI=Q&Last=Public"
### connect and send the server a path
    httpobj = httplib.HTTP('www.some-server.out-there', 80)
    httpobj.putrequest('POST', '/cgi-bin/some-cgi-script')
    ### now generate the rest of the HTTP headers...
    httpobj.putheader('Accept', '*/*')
    httpobj.putheader('Connection', 'Keep-Alive')
    httpobj.putheader('Content-type', 'application/x-www-form-urlencoded')
    httpobj.putheader('Content-length', '%d' % len(qs))
    httpobj.endheaders()
    httpobj.send(qs)
    ### find out what the server said in response...
    reply, msg, hdrs = httpobj.getreply()
    if reply != 200:
	sys.stdout.write(httpobj.getfile().read())
주목할 것은 일반적으로 "url로 코드 전환된 제출(url encoded posts)"에 대해서는 (기본) 질의 문자열이 반드시 "인용부호화 되어" , 예를 들면, 동등 사인(equals signs) 혹은 공백이 이름 혹은 값에서 나타날 때 코드전환된 형태로 변경되어야 한다는 것입니다. urllib.quote를 사용해서 이 인용부호 붙이기를 수행하세요. 예를 들어 name="Guy Steele, Jr."를 보내려면:

>>> from urllib import quote
   >>> x = quote("Guy Steele, Jr.")
   >>> x
   'Guy%20Steele,%20Jr.'
   >>> query_string = "name="+x
   >>> query_string
   'name=Guy%20Steele,%20Jr.'


4.62. bsddb (혹은 anydbm) 데이타베이스가 열릴 때 나의 프로그램이 충돌하면, 데이타 베이스가 깨져버립니다. 왜 그런지요?

bsddb과 함께 쓰기 접근으로 열린 데이타베이스는 (그리고 때로는 anydbm 모듈에 의해서 열리는데, 왜냐하면 우선적으로 bsddb를 사용할 것이기 때문입니다) 그 데이타베이스의 close 메쏘드를 사용하여 반드시 명시적으로 닫혀야 합니다. 기저의 libdb 패키지는 데이타베이스 내용을 임시저장하는데 디스크-상의 형태로 변경되어 씌여지는데 필요합니다. 일반적으로 열린 파일은 이와는 달라서, 커널의 쓰기 버퍼에 디스크-상 비트를 이미 가지고 있으며, 프로그램이 종료할 때 커널에 의해서 단지 덤프될 수만 있습니다.

만약 새로운 bsddb 데이타베이스를 초기화하였으나 그 프로그램이 충돌하기 전에 아무것도 쓰지 않았다면, 가끔은 길이-0인 파일을 가지게 되고 다음에 그 파일을 열때는 예외를 만나게 될 것입니다.


4.63. 파이썬 스크립트를 유닉스에서 어떻게 실행가능하도록 만드나요?

두 가지를 처리할 필요가 있습니다: 스크립트 파일의 모드는 실행가능으로 설정되어 있어야 하고 ( 'x' 비트를 포함하여), 그리고 첫 번재 라인은 반드시 #!로 시작되고 다음에 파이썬 인터프리터에 대한 경로명이 따라와야 합니다.

첫 번째는 'chmod +x scriptfile' 또는 'chmod 755 scriptfile'를 실행함으로써 달성됩니다.

두 번째는 여러 방식으로 달성될 수 있습니다. 가장 쉬운 방법은 다음과 같은 라인을

  #!/usr/local/bin/python
파일의 바로 첫 번째 라인을 작성하는 것입니다 - 또는 파이썬 인터프리터가 여러분의 플랫폼에 설치되어 있는 어떤 경로명이라도 좋습니다.

파이썬 인터프리터가 있는 곳에 상관 없이 그 스크립트를 실행하고 싶다면, "env" 프로그램을 사용할 수 있습니다. 거의 모든 플랫폼에서 다음은 잘 작동할 것입니다, 파이썬 인터프리터가 사용자의 $PATH가 지정하는 디렉토리에 있다는 가정한다면:

#! /usr/bin/env python
주의 -- CGI 스크립트에 대해서는 이렇게 *하지 마세요*. CGI 스크립트에 대한 $PATH 변수는 아주 작습니다, 그래서 파이썬 인터프리터의 실제적인 절대 경로명을 사용할 필요가 있습니다.

때때로, 사용자의 환경은 꽉 차서 /usr/bin/env 프로그램이 실패합니다; 또는 전혀 env 프로그램이 없을 수도 있습니다. 그러한 경우에는, 다음의 (알렉스 레진스키(Alex Rezinsky)의 배려에 의한) 임시 변통을 사용해 볼 수 있습니다:

  #! /bin/sh
  """:"
  exec python $0 ${1+"$@"}
  """
단점이라면 이것이 그 스크립트의 __doc__ 문자열이 되어버린다는 것인데, 그렇지만 다음과 같이 덧 붙여서 그것을 해결할 수 있습니다.

  __doc__ = """...Whatever..."""


4.64. 어떻게 리스트로부터 중복을 제거하나요?

일반적으로, 그 리스트를 재정렬하는데 개의치 않는다면

   if List:
      List.sort()
      last = List[-1]
      for i in range(len(List)-2, -1, -1):
          if last==List[i]: del List[i]
          else: last=List[i]
만약 그 리스트의 모든 요소들이 사전의 키로 사용된다면 (즉, 모두 해쉬계산이 가능하다면) 이것은 어떤 때는 더 빠릅니다.

   d = {}
   for x in List: d[x]=x
   List = d.values()
또한, 굉장히 거대한 리스트에 대해서 더 최적의 대안은 첫 번째 방법이라고 생각할 것입니다. 두 번째 대안은 사용될 수 있을 때마다 아주 훌륭합니다.


4.65. 파이썬에서 알려진 2000년 문제가 있나요?

파이썬 1.5에서 2000년 결함이 있다는 것은 감지하지 못했습니다. 파이썬은 거의 날짜 계산을 하지 않습니다 그리고 필요가 있다면, C 라이브러리 함수에 의존합니다. 파이썬은 일반적으로 시간을 1970년 이후의 초단위로 나타내던가 혹은 터플로 (year, month, day, ...) 나타내는데, year는 네 개의 자리수로 표현되므로, Y2K 버그를 만들 것 같지는 않아 보입니다. 그래서 C 라이브러리가 이상없는한, 파이썬 역시 이상없습니다. 물론, 나는 여러분의 파이썬 코드를 보증할 수는 없습니다!

자유롭게 얻을 수 있는 소프트웨어의 본성상, 나는 이 진술이 법적으로 구속력이 없다는 것을 추가 해야 할 필요가 있습니다. 파이썬의 복사권 고지사항에는 다음의 권리부인이 있습니다:

  STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH    
  REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF           
  MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH   
  CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL     
  DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR    
  PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER          
  TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR          
  PERFORMANCE OF THIS SOFTWARE.                                            

  어떠한 특별한, 간접적 혹은상당한 피해에 대해서도, 
  혹은 데이타, 이익의 망실,사용불능으로 인한 어떤 피해에 대해서도,
  소프트웨어의 수행 혹은 사용과 관련한 혹은 야기된,
  소홀행위, 계약행위 혹은 다른 강제 행위등
  상업적이용과 최적화에 대한 모든 묵시적 보증을포함하여, 
  어떤 경우라도 CNRI는 이 소프트웨어에 대한 모든 보증을 부인한다
좋은 소식은 만약 여러분이 문제에 봉착하면, 전체 소스를 얻을 수 있어서 그것을 추적하여 문제를 수정할 수 있다는 것입니다!


4.66. 일련의 객체들에 메쏘드를 적용하는 map 버전을 원합니다! 도와 주세요!

상상해 보세요!

  def method_map(objects, method, arguments):
       """method_map([a,b], "flog", (1,2)) gives [a.flog(1,2), b.flog(1,2)]"""
       nobjects = len(objects)
       methods = map(getattr, objects, [method]*nobjects)
       return map(apply, methods, [arguments]*nobjects)
map, apply, getattr 그리고 파이썬의 다른 동적 사양들의 신비를 이해하는 것은 일반적으로 좋은 생각입니다.


4.67. 파이썬에서 어떻게 무작위 수를 생성하나요?**

표준 라이브러리 모듈 "random"은 무작위 수 생성기를 구현하고 있습니다. 사용법은 간단합니다:

    import random
    random.random()
이것은 [0, 1) 범위의 무작위적인 부동소수점 수를 반환합니다.

이 모듈에는 다른 특별한 생성자(generator)도 있습니다:

    randrange(a, b)는 [a, b) 범위의 정수를 선택합니다.
    choice(S)는 주어진 연속열에서 선택합니다.
    uniform(a, b)는 [a, b) 범위의 부동소수점 수를 선택합니다.
무작위 수 생성기의 초기화 설정을 강제하려면, 다음을 사용하세요.

    seed(x, y, z)는 [1, 256) 사이의 세 개의 정수로부터 씨 값을 설정합니다. 
Random이라는, 클래스도 있는데 그것을 초기화하여 독립적인 다중 무작위 수 생성기를 만들 수 있습니다.

그 모듈은 또한 다양한 표준 배포본에 준하는 함수들을 담고 있습니다.

이 모든 것은 라이브러리 참조 매뉴얼에 문서화 되어 있습니다. 모듈 "whrandom"은 폐기되었다는 것을 주의하세요.


4.68. 어떻게 직렬 (RS232) 포트에 접근하나요?

윈도우에 (RS 232 직렬 포트를 통한 통신을 위한) 직렬 통신 모듈이 있습니다. 다음 참조:

  ftp://ftp.python.org/pub/python/contrib/sio-151.zip
  http://www.python.org/ftp/python/contrib/sio-151.zip
도스를 위해서는, 한스 노박의 Python-DX를 시험해 보세요, 이것을 지원합니다, 다음 참조:

  http://www.cuci.nl/~hnowak/
유닉스를 위해서는, (http://www.python.org/search/를 사용하여) 데자 뉴스를 탐색하셔서 저자가 미치 채프만(Mitch Chapman)인 "serial port"를 찾아 보세요 (그의 글을 여기에 포함시키기에는 약간 길군요).


4.69. Tk-Buttons에 관한 이미지가 Py15에서 작동하지 않습니다?

분명히 작동합니다, 그러나 먼저 그 이미지 객체에 대한 자신만의 참조점을 유지해야 합니다. 더 자세히 설명하면, 확인해야 할 것은, 예를 들어, 전역 변수 혹은 클래스 속성이 그 객체를 참조하고 있는지를 확인해야 합니다.

메일링 리스트로부터 프레드릭 룬트(Fredrik Lundh)를 인용함:

  먼저, Tk 버튼 위젯은 내부의 photoimage 객체에 대한 참조점을 유지하고 있지만, 
  Tkinter는 그렇지 않습니다.  그래서 파이썬의 마지막 참조점이 사라지면, 
  Tkinter는 Tk에게 photoimage를 해제하도록 명령합니다.  그러나 그 이미지는 위젯이
  사용하고 있으므로, Tk는 그것을 파괴하지 않습니다. 완전하게는 아닙니다.  
  그 이미지를 공백화 하여서, 완전히 투명하게 만들어 버리는데...
  네 그렇습니다, 1.4에서 처리하는 키워드 인수에는, 어떤 경우에 여분의 참조점을 
  유지하는 버그가 있었습니다. 그리고 귀도가 그 버그를 1.5에서 고쳤을 때는,
  상당량의 Tkinter 프로그램들을 망가 뜨렸습니다....


4.70. math.py (socket.py, regex.py, 등등.) 소스 파일은 어디에 있나요?

모듈에 대한 소스 파일을 찾을 수 없다면 그것은 C, C++ 혹은 다른 컴파일 언어로 구현된 내장 혹은 동적으로 적재된 모듈일 수 있습니다. 이 경우에 소스 파일을 가질 수 없거나 혹은 (파이썬 경로가 아닌) C 소스 디렉토리의 어디엔가에 있는, mathmodule.c와 같은 어떤 것일 수 있습니다.

프레드릭 룬트(Fredrik Lundh) (fredrik@pythonware.com)가 설명한 바에 의하면 (파이썬-리스트에서):

(적어도) 세 가지 종류의 모둘이 파이썬에 있습니다: 1) 파이썬으로 작성된 모듈 (.py); 2) C로 작성되고 동적으로 적재되는 모듈 (.dll, .pyd, .so, .sl, 등등); 3) C로 작성되고 인터프리터와 연결된 모듈; 이러한 것들의 리스트를 얻으려면, 다음과 같이 타자하세요:

    import sys
    print sys.builtin_module_names


4.71. 파이썬 스크립트로부터 어떻게 메일을 보내나요?

유닉스에서는, sendmail을 사용하면, 대단히 용이합니다. sendmail 프로그램의 위치는 시스템에 따라 다릅니다; 어떤 때는 /usr/lib/sendmail에 있고, 어떤 때는 /usr/sbin/sendmail에 있습니다. sendmail 매뉴얼 페이지를 보시면 도움이 될 것입니다. 여기에 약간의 예제 코드가 있습니다:

  SENDMAIL = "/usr/sbin/sendmail" # sendmail location
  import os
  p = os.popen("%s -t" % SENDMAIL, "w")
  p.write("To: cary@ratatosk.org\n")
  p.write("Subject: test\n")
  p.write("\n") # blank line separating headers from body
  p.write("Some text\n")
  p.write("some more text\n")
  sts = p.close()
  if sts != 0:
      print "Sendmail exit status", sts
비-유닉스 시스템에서는 (그리고 물로, 유닉스 시스템에서도!), SMTP를 사용하여 메일을 이웃의 메일 서버에 보낼 수 있습니다. 파이썬 1.5.1 이후로 SMTP를 위한 라이브러리 smtplib.py가 포함되었습니다. 여기에 대단한 간단한 상호대화적 메일 송신자가 그것을 사용하고 있습니다. 이 방법은 SMTP 수신자를 지원하는 어떠한 호스트에 대해서도 잘 작동할 것입니다; 그렇지 않으면, 사용자에게 호스트를 요구해야 할 것입니다:

    import sys, smtplib
    fromaddr = raw_input("From: ")
    toaddrs  = string.splitfields(raw_input("To: "), ',')
    print "Enter message, end with ^D:"
    msg = ''
    while 1:
        line = sys.stdin.readline()
        if not line:
            break
        msg = msg + line
    # The actual mail send
    server = smtplib.SMTP('localhost')
    server.sendmail(fromaddr, toaddrs, msg)
    server.quit()


4.72. 소켓에 대한 connect()에서 블로킹을 어떻게 피하나요?

select 모듈은 일단 연결되면 소켓에 대한 비동기 입출력(I/O)에 도움이 되는 것으로 잘 알려져 있습니다. 그렇지만, 초기의 connect() 호출에서 블로킹을 피하는 법은 잘 알려져 있지 않습니다. 제레미 힐튼(Jeremy Hylton)은 다음의 충고를 합니다 (약간 수정됨):

TCP 연결이 블로킹 되는 것을 방지하려면, 그 소켓을 비-블로킹(non-blocking) 모드로 설정할 수 있습니다. 그리고 나서 connect()를 실행하면, (그럴것 같지는 않겠지만) 즉각 연결되거나 혹은 에러번호(errno)를 담은 예외를 얻습니다. errno.EINPROGRESS는 연결이 진행중이지만, 아직 완료되지 않았다는 것을 나타냅니다. 다른 운영체제에서는 다른 errnos를 반환합니다, 그래서 여러분은 점검해볼 필요가 있습니다. 확실하게 말해 줄 수 있는 것은 다른 버전의 솔라리스는 서로 다른 errno 값을 반환한다는 것입니다.

파이썬 1.5 이상에서는, connect_ex()를 사용하여 예외를 생성하는 것을 피할 수 있습니다. 그것은 단지 errno 값만을 반환할 것입니다.

탐지(poll)를 하려면, connect_ex()를 나중에 또 다시 호출할 수 있습니다 -- 0 또는 errno.EISCONN는 연결되어 있다는 것을 나타냅니다 -- 또는 이 소켓을 셀렉트(select)에 건네주어 (그것이 쓰기 가능한가를 점검할 수 있습니다).


4.73. 어떻게 16진수와 8진 정수를 지정하나요?

8진 자리를 지정하기 위해서는, 그 8진 값의 앞쪽에 0(제로)를 두세요. 예를 들어, 변수 "a"에 8진 값 "10"( 10진수로는 8)을 설정하려면, 다음과 같이 타자하세요:

    >>> a = 010
이것이 작동하는지 확인하려면, 인터프리터에서 "a"를 타자하고 엔터를 치면, 파이썬이 "a"의 현재 값을 10진수로 토해 낼 것입니다:

    >>> a
    8
16진수도 마찬가지로 쉽습니다. 간단하게 그 16진수의 앞에 0(제로)를 두고, 다음에 소문자 "x"를 두세요. 16진 숫자는 소문자 혹은 대문자로 지정될 수 있습니다. 예를 들어, 파이썬 인터프리터에서는:

    >>> a = 0xa5
    >>> a
    165
    >>> b = 0XB2
    >>> b
    178


4.74. 한 번에 한 개의 키눌림을 획득하는 법?

윈도우에 대해서는, 질문 8.2를 참조하세요. 여기에 유닉스를 위한 답변이 있습니다.

다수의 해결책이 있습니다; 어떤 것은 curses를 사용하는 것과 관련되는데, 그것은 배우기에 대단히 큽니다. 여기에 앤드류 쿠클링(Andrew Kuchling)의 배려에 의한, curses를 사용하지 않는 해결책이 있습니다 (PGP-스타일의 무작위수 바구니 만들기 코드로부터 인용함):

        import termios, TERMIOS, sys, os
        fd = sys.stdin.fileno()
        old = termios.tcgetattr(fd)
        new = termios.tcgetattr(fd)
        new[3] = new[3] & ~TERMIOS.ICANON & ~TERMIOS.ECHO
        new[6][TERMIOS.VMIN] = 1
        new[6][TERMIOS.VTIME] = 0
        termios.tcsetattr(fd, TERMIOS.TCSANOW, new)
        s = ''    # We'll save the characters typed and add them to the pool.
        try:
            while 1:
                c = os.read(fd, 1)
                print "Got character", `c`
                s = s+c
        finally:
            termios.tcsetattr(fd, TERMIOS.TCSAFLUSH, old)
이것이 작동하려면 termios 모듈이 필요합니다, 그리고 리눅스에서만 시도해 보았을 뿐이지만, 다른 곳에서도 작동할 것입니다. 그것은 stdin의 반향을 끄고 기준(canonical) 모드를 사용불가로 하고, 그리고 나서 한 번에 한 글자씩 표준입력으로부터 읽어들이며, 각 키눌림 이후에는 아무것도 읽어 들이지 않습니다.


4.75. 파이썬에서 어떻게 구성자 (혹은 메쏘드)를 덮어 쓸 수 있나요?

(이것은 실제로 모든 메쏘들에 적용됩니다, 그러나 웬일인지 그 질문은 보통 구성자의 문맥에서 먼저 나타납니다.)

C++으로는 다음과 같이 작성하는 곳에서

    class C {
        C() { cout << "No arguments\n"; }
        C(int i) { cout << "Argument is " << i << "\n"; }
    }
파이썬에서는 기본 인수들을 사용하여, 모든 경우들을 나포하는 한 개의 구성자를 작성하여야 합니다, 예를 들어:

    class C:
        def __init__(self, i=None):
            if i is None:
                print "No arguments"
            else:
                print "Argument is", i
이것은 전적으로 동등한 것은 아니지만, 실용적으로는 충분히 근접합니다.

가변-길이 인수 리스트를 시험해 볼 수도 있습니다, 예를 들어.

        def __init__(self, *args):
            ....
같은 접근법이 모든 메쏘드 정의에 대하여 작동합니다.


4.76. 어떻게 키워드 인수를 하나의 메쏘드에서 다른 메쏘드로 건네나요?

apply를 사용하세요. 예를 들어:

    class Account:
        def __init__(self, **kw):
            self.accountType = kw.get('accountType')
            self.balance = kw.get('balance')
    class CheckingAccount(Account):
        def __init__(self, **kw):
            kw['accountType'] = 'checking'
            apply(Account.__init__, (self,), kw)
    myAccount = CheckingAccount(balance=100.00)
파이썬 2.0에서는 그것을 새로운 ** 구문을 사용하여 직접 호출할 수 있습니다:

    class CheckingAccount(Account):
        def __init__(self, **kw):
            kw['accountType'] = 'checking'
            Account.__init__(self, **kw)
혹은 더욱 일반적으로:

 >>> def f(x, *y, **z):
 ...  print x,y,z
 ...
 >>> Y = [1,2,3]
 >>> Z = {'foo':3,'bar':None}
 >>> f('hello', *Y, **Z)
 hello (1, 2, 3) {'foo': 3, 'bar': None}


4.77. HTML을 만들기 위해 도움을 받으려면 어떤 모듈을 사용해야 하나요?

로빈 프리드리히(Robin Friedrich)가 작성한 HTMLgen을 점검하세요. 그것은 모든 HTML 3.2 마크업 태그에 상응하는 객체들을 가진 클래스 라이브러리입니다. 파이썬으로 작성하고 있을 때 그리고 웹 페이지를 만들거나 혹은 CGI 폼 등등을 만들기 위해 HTML 페이지를 합성하기를 원할 때에 사용됩니다.

그것은 python.org 또는 Starship에 있는 FTP 공헌 지역에서 찾을 수 있습니다. 탐색 엔진을 사용하여 최신 버전을 찾아 보세요.

또한 파이썬 코드와 HTML 코드 사이를 명확하게 갈라주는, 문서임시원형(DocumentTemplate)을 고려하는 데에 유용할지도 모릅니다. 임시문서원형(DocumentTemplate)은 Bobo 객체 출판 시스템의 (http:/www.digicool.com/releases) 일부이지만 물론 독립적으로 사용될 수 있습니다!


4.78. 문서화 문자열로부터 어떻게 문서를 생성하나요?

gendoc을 사용하세요, Daniel Larson이 만들었습니다. 다음을 참조하세요

http://starship.skyport.net/crew/danilo/

이것은 파이썬 소스 코드에 있는 문서화 문자열로부터 HTML을 만들어 낼 수 있습니다.


4.79. 어떻게 이진 데이타를 읽거나 (또는 쓸수) 있나요?

복잡한 데이타 포맷에 대해서는, struct(구조) 모듈을 사용하는 것이 가장 좋습니다. 그것은 라이브러리 참조서에 문서화 되어 있습니다. 그것으로 이진 데이타를 (보통은 숫자들을) 담고 있는 파일로 부터 문자열을 취할 수 있으며 그것을 파이썬 객체로 변환할 수도 그리고 그 반대로 할 수도 있습니다;

예를 들어, 다음의 코드는 두 개의 2-바이트 정수와 한 개의 4-바이트 정수를 한 파일로 부터 큰값-종료형(big-endian) 포맷으로 읽습니다:

  import struct
  f = open(filename, "rb")  # Open in binary mode for portability
  s = f.read(8)
  x, y, z = struct.unpack(">hhl", s)
포맷 문자열 속에 있는 '>'는 큰값-종료형 데이타를 강제합니다; 그 문자열로부터 문자 'h'는 한개의 "단정도 정수(2바이트)"를 읽어 들이고, 그리고 'l'은 한개의 "배정도 정수(4 바이트)"를 읽어 들입니다.

더욱 규칙적인 데이타 (예. 정수 혹은 실수의 동질적인 리스트)에 대해서는, 배열(array) 모듈도 사용할 수 있으며, 라이브러리 참조서에 문서화되어 있습니다.


4.80. 키 엮음을 Tkinter에서 작동시킬 수 없습니다

자주-들리는 불평에 의하면, bind() 메쏘드로 사건에 엮인 사건 처리자가, 적절한 키가 눌려질 때 조차 처리되지 않는다고 합니다.

가장 흔한 원인은 엮임이 적용되는 그 위젯이 "키보드 초점(keyboard focus)"을 가지지 않는 것입니다. 초점 명령어에 대해서는 Tk 문서를 참조하세요. 보통 위젯에는 자신 안에 클릭이 되면 키보드 초점이 주어집니다 (그러나 라벨에 대해서는 아닙니다; (초점 취하기) taketocus(takefocus?) 선택사항을 참조하세요).


4.81. "import crypt"가 실패합니다

[유닉스]

파이썬 1.5부터는, crypt 모듈이 기본으로 설정불가입니다. 그것을 설정가능토록 하기 위해서는, 파이선 소스 트리로 들어가 파일 Modules/Setup을 편집해서 가능하도록 해야 합니다 ('#crypt'로 시작하는 라인 앞의 '#' 표식을 지우세요). 그리고 재구축하세요. 또한 같은 라인에 문자열 '-lcrypt'를 추가해야할 필요가 있을수도 있습니다.


4.82. 파이썬 프로그램에 대한 코딩 표준 혹은 스타일 지도서가 있나요?

네, 귀도가 "파이썬 스타일 지도서(Python Style Guide)"를 썼습니다. 다음 essays/styleguide.html을 보세요


4.83. 어떻게 Tkinter 어플리케이션을 독립실행파일로 만드나요?

Freeze는 독-립적인 어플리케이션을 생성하는 도구입니다 (4.28 참조).

Tkinter 어플리케이션을 얼릴 때, 그 어플리케이션은 진짜로 독-립적이 되지는 않을 것입니다, 그 어플리케이션은 여전히 tcl과 tk 라이브러리를 필요로 합니다.

하나의 해결책은 그 어플리케이션을 tcl와 tk 라이브러리와 함께 담고서, 환경 변수 TCL_LIBRARY와 TK_LIBRARY를 사용하여 실행-시간에 그것들을 지시하는 것입니다.

진짜로 독-립적인 어플리케이션을 얻으려면, 그 라이브러리를 형성하는 Tcl 스크립트가 그 어플리케이션에 역시 통합되어야할 필요가 있습니다. 그러한 것을 지원하는 하나의 도구는 SAM (stand-alone modules)인데, Tix 배포본에 (http://tix.mne.com/) 포함되어 있습니다. Tix를 SAM 사용가능으로 구축하시고, 파이썬의 Modules/tkappinit.c 안에서 Tclsam_init 등등에 대한 적절한 호출을 수행하세요, 그리고 libtclsam와 libtksam에 연결하세요 (Tix 라이브러리 역시 포함해야할 수도 있습니다).


4.84. 어떻게 정적 클래스와 정적 클래스 메쏘드를 만드나요?

[팀 피터스(Tim Peters), tim_one@email.msn.com]

정적 데이타는 (C++ 혹은 Java의 관점에서는) 쉽습니다; 정적 메쏘드는 (또다시 C++ 혹은 Java 관점으로 보아) 직접적으로 지원되지 않습니다.

정적 데이타 (STATIC DATA)

예를 들어,

    class C:
        count = 0   # number of times C.__init__ called
        def __init__(self):
            C.count = C.count + 1
        def getcount(self):
            return C.count  # or return self.count
c.count는 또한 isinstance(c, C)가 보유하는 모든 C에 대하여 C.count를 참조합니다, c 그 자체에 의해서 덮여 씌여지거나 혹은 c.__class__에서부터 거꾸로 C까지의 기본-클래스 탐색 경로에 있는 어떤 클래스에 의하여 덮여씌여지지만 않는다면 말이지요.

주의: C의 메쏘드 안에서 다음라인은,

    self.count = 42
연관성없는 새로운 "count"라는 이름의 실체 변수를 self의 사전안에 생성합니다. 그래서 클래스-정적 데이타 이름을 다시 엮으려면 다음의 형태가

    C.count = 314
메쏘드 안이든 밖이든 필요합니다.

정적 메쏘드(STATIC METHODS)

정적 메쏘드는 (정적 데이타와 대조하여) 파이썬에서 자연스럽지 못합니다, 왜냐하면 다음은

    C.getcount
묶여지지 않은 메쏘드 객체를 반환하는데, C의 실체가 첫 번째 인수로 제공되지 않고서는 호출될 수 없기 때문입니다.

정적 메쏘드의 효과를 얻기 위한 의도적인 방법은 모듈-수준의 함수를 이용하는 것입니다:

    def getcount():
        return C.count
만약 여러분의 코드가 모듈당 하나의 클래스를 정의하도록 구조화되었다면 (혹은 긴밀하게 연관된 클래스 계층도라면), 이것은 원하는 바의 캡슐화를 제공합니다.

데자뉴스를 탐색해보면 정적 메쏘드를 만들어 보기 위한 머리싸매는 전략들을 많이 볼 수 있습니다. 대부분의 사람들은 그러한 치료약이 그 병보다도 더 나쁘다고 느낍니다. 아마도 제일 약한 독성이라면 페카 페시(Pekka Pessi) (mailto:ppessi@hut.fi)에게 돌리겠습니다:

    # helper class to disguise function objects
    class _static:
        def __init__(self, f):
            self.__call__ = f
    class C:
        count = 0
        def __init__(self):
            C.count = C.count + 1
        def getcount():
            return C.count
        getcount = _static(getcount)
        def sum(x, y):
            return x + y
        sum = _static(sum)
    C(); C()
    c = C()
    print C.getcount()  # prints 3
    print c.getcount()  # prints 3
    print C.sum(27, 15) # prints 42


4.85. __import__('x.y.z')는 <module 'x'>를 반환합니다; 어떻게 z를 얻나요?

다음과 같이 해보세요

   __import__('x.y.z').y.z
더 현실적인 상황에 대해서는, 다음과 같이 해야할 지도 모르겠습니다

   m = __import__(s)
   for i in string.split(s, ".")[1:]:
       m = getattr(m, i)


4.86. 기본적인 쓰레드 상식

꼭 주의하실 것은 파이썬 2.1 현재로 파이썬의 쓰레드 모델을 사용하여 다중 처리 하드웨어를 이용할 방법은 없습니다. 파이썬은 전역 자물쇠 (global lock)을 사용하는데, 다중 스레드가 동시에 작동하는 것을 허용하지 않습니다.

만약 다음과 같은 간단한 테스트 프로그램을 작성해 보시면:

  import thread
  def run(name, n):
      for i in range(n): print name, i
  for i in range(10):
      thread.start_new(run, (i, 100))
어떤 쓰레드도 실행되지 않는 듯이 보입니다! 그 이유는 주 쓰레드가 종료하자 마자, 모든 쓰레드가 사망하기 때문입니다.

간단한 해결책은 그 프로그램의 마지막에 sleep을 추가하는 것인데, 모든 쓰레드가 끝나기 위해서 충분히 긴 시간을 주는 것입니다:

  import thread, time
  def run(name, n):
      for i in range(n): print name, i
  for i in range(10):
      thread.start_new(run, (i, 100))
  time.sleep(10) # <----------------------------!
그러나 이제 (많은 플랫폼에서) 그 쓰레드들은 병렬적으로 실행되지 않습니다, 그러나 한번에 하나씩, 연속적으로 실행되는 듯이 보입니다! 그 이유는 OS의 쓰레드 스케쥴러가 이 전의 쓰레드가 정지당할 때까지는 새로운 쓰레드를 시작시키지 않기 때문입니다.

간단한 해결책은 작은 sleep을 그 실행 함수의 시작부에 추가하는 것입니다:

  import thread, time
  def run(name, n):
      time.sleep(0.001) # <---------------------!
      for i in range(n): print name, i
  for i in range(10):
      thread.start_new(run, (i, 100))
  time.sleep(10)
더 힌트를 들자면:

time.sleep() 호출을 마지막에 사용하는 대신에, 세마포어 메카니즘류의 것을 사용하는 것이 더 좋습니다. 하나의 아이디어는 Queue 모듈을 사용하여 queue 객체를 생성하고, 각 쓰레드가 종료할 때 그 큐에 토큰을 추가하도록 하며, 주 쓰레드가 쓰레드 수만큼의 토큰을 그 큐로부터 읽도록 하는 것입니다.

쓰레드 모듈 대신에 그 쓰레딩 모듈을 사용하세요. 그것은 파이썬 버전 1.5.1이후에 포함되어 있습니다. 그것은 이러한 자질구레한 모든 것들을 처리해 주며, 다른 많은 멋진 사양들 역시 가지고 있습니다!


4.87. sys.stdout (stdin, stderr)을 닫았는데 왜 실제로 닫히지 않나요?

파이썬 파일 객체는 C 스트림의 위에 쌓아 놓은 고-수준 추상화 층이며, C 스트림은 이번에는 (다른 것들 중에) 저-수준 C 파일 기술자 위에 쌓은 중-수준 추상화 층입니다.

파이썬에서는 대부분의 파일 객체 f를 위해서 내장 함수 "open"을 통하여 작성하는데, f.close()는 파이썬의 관점에서 보면 그 파일 객체에 닫혀진 것으로 표식을 남기며, 또한 기저에 있는 C 스트림을 닫도록 조치합니다. f가 쓰레기가 되면, f의 소멸자 안에서 이것 역시 자동적으로 일어납니다.

그러나 stdin, stdout 그리고 stderr는 파이썬에서 특별하게 취급되는데, C 에 의해서도 특별한 지위가 주어지기 때문입니다: 다음과 같이 하면

    sys.stdout.close() # ditto for stdin and stderr
파이썬-수준의 파일 객체를 닫혀진 것으로 표식을 남깁니다, 그러나 (만약 sys.stdout이 여전히 그의 기본 값에 엮여 있다면, 그것 역시 C가 "stdout"이라고 부르는 스트림입니다) 그와 관련된 C 스트림을 닫지 않습니다.

이러한 세개중 하나를 위한 기저의 C 스트림을 닫으려면, 그것이 진짜 원하는 것인지를 먼저 확인해야 합니다 (예를 들어, 여러분은 입출력을 시도하는 확장 모듈과 그 조작을 혼동할 수도 있습니다). 만약 그렇다면, os.close를 사용하세요:

    os.close(0)   # close C's stdin stream
    os.close(1)   # close C's stdout stream
    os.close(2)   # close C's stderr stream


4.88. 어떤 종류의 전역 값 변환이 쓰레드-안전 한가요?

[adapted from c.l.py responses by Gordon McMillan &GvR]

전역 인터프리터 잠금은 한 번에 오직 한 개의 쓰레드가 파이썬 가상기계에서 실행되는가를 내부적으로확인하기 위해 사용됩니다. 일반적으로, 파이썬은 오직 바이트코드 지시어 사이에서만 쓰레드간 전환을 제공합니다 (얼마나 자주 전환을 제공하느냐는 sys.setcheckinterval를 통하여 설정될 수 있습니다). 각 바이트코드 지시어는 -- 그리고 그것으로부터 도달되는 모든 C 구현 코드는 -- 그러므로 원자적입니다.

이론적으로, 이것이 의미하는 바는, 정확한 계산을 위해서는 PVM 바이트 코드 구현에 대한 정확한 이해를 요구한다는 것입니다. 실제적으로, 이것이 의미하는 바는, "원자적으로 보이는" 내장 데이타(정수, 리스트, 사전, 등등) 형인 공유 변수들에 대한 처리가 진짜로 원자적이라는 것입니다.

예를 들어, 이러한 것들은 원자적입니다 (L, L1, L2은 리스트이며 , D, D1, D2는 사전, x, y는 객체이고, i, j 는 정수입니다):

    L.append(x)
     L1.extend(L2)
    x = L[i]
    x = L.pop()
    L1[i:j] = L2
    L.sort()
    x = y
    x.field = y
    D[x] = y
    D1.update(D2)
    D.keys()
이러한 것들은 원자적이지 않습니다:

    i = i+1
    L.append(L[-1])
    L[i] = L[j]
    D[x] = D[x] + 1
주의: 다른 객체들을 대체하는 연산은 참조횟수가 0 에 도달 할 때 다른 객체들의 __del__ 메쏘드를 호출할 가능성이 있습니다, 그리고 그것은 다른 것들에 영향을 미칠 수 있습니다. 이것은 특히 사전과 리스트에 대한 대량의 갱신에도 적용됩니다. 의심스러울 때는, mutex를 사용하세요!


4.89. 어떻게 적절하게 문자열을 수정하나요?

문자열을 변경불가입니다 (질문 6.2 참조) 그래서 직접적으로는 문자열을 수정할 수 없습니다. 이러한 기능을 가지는 객체가 필요하면, 그 문자열을 리스트로 변환해 보시거나 혹은 배열(array) 모듈을 살펴 보세요.

    >>> s = "Hello, world"
    >>> a = list(s)
    >>> print a
    ['H', 'e', 'l', 'l', 'o', ',', ' ', 'w', 'o', 'r', 'l', 'd']
    >>> a[7:] = list("there!")
    >>> import string
    >>> print string.join(a, '')
    'Hello, there!'
    >>> import array
    >>> a = array.array('c', s)
    >>> print a
    array('c', 'Hello, world')
    >>> a[0] = 'y' ; print a
    array('c', 'yello world')
    >>> a.tostring()
    'yello, world'


4.90. 키워드/선택적인 매개변수/인수들을 건네는 법

Q: 어떻게 하나의 함수로부터 선택적인 혹은 키워드 매개변수를 또 다른 함수에
   건네 줄수 있나요?
A: 'apply'를 사용하세요, 다음과 같이:

	def f1(a, *b, **c):
		...

	def f2(x, *y, **z):
		...
		z['width']='14.3c'
		...
		apply(f1, (x,)+y, z)


4.91. 어떻게 사전이 일관된 순서로 그 키들을 출력도록 하나요?

일반적으로, 사전은 키를 예상할 수없는 순서로 저장합니다, 그래서 사전의 요소들을 출력하는 순서도 비슷하게 예상할 수 없습니다. (질문 6.12를 보시면 왜 그런지 이해하실 수 있습니다.)

만약 출력가능 버전을 파일에 저장하고, 약간의 변경을 하고 나서 그것을 다른 어떤 출력된 사전과 비교해 보기를 원한다면 이것은 고민스러울 수 있습니다. 만약 그러한 필요성이 있다면 UserDict.UserDict를 하부클래스화하여 예상가능한 순서로 자신을 출력하는 SortedDict 클래스를 만들 수 있습니다. 여기에 그러한 클래스를 간결하게 구현한 클래스가 있습니다:

  import UserDict, string
  class SortedDict(UserDict.UserDict):
    def __repr__(self):
      result = []
      append = result.append
      keys = self.data.keys()
      keys.sort()
      for k in keys:
        append("%s: %s" % (`k`, `self.data[k]`))
      return "{%s}" % string.join(result, ", ")
    ___str__ = __repr__

비록 완벽한 해결책은 아니지만, 이것은 마주칠 수 있는 일반적인 많은 상황에 잘 작동할 것입니다. (그것은 pprint 모듈에 어떠한 영향도 미치지 않을 것입니다 그리고 사전이든가 혹은 사전을 포함한 값들을 투명하게 처리하지 않을 것입니다).


4.92. 파이썬 지침서가 있습니까?

네, 다음 pyfaq01.htm#1.20 질문 1.20을 참조하세요


4.93. 어떻게 파이썬 어플리케이션을 독-립적인 프로그램으로 컴파일하나요?

비록 개발되고 있는 파이썬 컴파일러가 있기는 하지만, 원하는 바가 독-립적인 프로그램이라면, 아마도 실제(real) 컴파일러가 필요하지는 않을 것입니다.

하나는 freeze 도구를 사용하는 것인데, 파이썬 소스 트리에 Tools/freeze로 포함되어 있습니다. 그것은 파이썬 바이트 코드 C 배열로 변환합니다. C 컴파일러를 사용해서, 여러분의 모든 모듈을 새로운 프로그램으로 내장할 수 있습니다, 그러면 표준 파이썬 모듈과 연결됩니다.

윈도우에서, 또다른 해결책이 존재하는데 C 컴파일러를 필요로 하지 않습니다. 크리스챤 디스머(Christian Tismer)의 SQFREEZE (http://starship.python.net/crew/pirx/)는 그 바이트 코드를 특별하게-준비된 파이썬 인터프리터에 추가합니다, 그 인터프리터는 그 바이트 코드를 실행형으로 이해할 것입니다.

고든 맥밀란(Gordon McMillian)이 제공하는 설치기는 (http://starship.python.net/crew/gmcm/distribute.html) 세번째 대안으로서, SQFREEZE와 유사하게 작동하지만, 임의적인 추가 파일도 그 독립 이진 파일에 포함하도록 허용합니다.


4.94. 어떻게 블로킹 없이 하나의 키눌림을 얻나요?

다수의 해결책이 있습니다; 어떤 것은 curses를 사용하는 것인데, 대단히 배우기 어렵습니다. 여기에 curses를 사용하지 않는 해결책이 있습니다.

        import termios, TERMIOS, fcntl, FCNTL, sys, os
        fd = sys.stdin.fileno()
        oldterm = termios.tcgetattr(fd)
        newattr = termios.tcgetattr(fd)
        newattr[3] = newattr[3] & ~TERMIOS.ICANON & ~TERMIOS.ECHO
        termios.tcsetattr(fd, TERMIOS.TCSANOW, newattr)
        oldflags = fcntl.fcntl(fd,FCNTL.F_GETFL)
        fcntl.fcntl(fd,FCNTL.F_SETFL,oldflags|FCNTL.O_NONBLOCK)
        try:
            while 1:
                try:
                 c = sys.stdin.read(1)
                  print "Got character", `c`
                except IOError:  pass   # Ignore IOError from empty buff
        finally:
            termios.tcsetattr(fd, TERMIOS.TCSAFLUSH, oldterm)
            fcntl.fcntl(fd,FCNTL.F_SETFL,oldflags)
이것이 작동하려면 termios와 fcntl 모듈이 필요합니다, 리눅스에서만 시도해 보았지만, 다른 곳에서도 작동하리라 봅니다.

이 코드에서는, 문자들이 한 번에 한개씩 읽혀지고 출력됩니다.

termios.tcsetattr()은 stdin의 반향을 끄고 표준(canonical) 모드를 사용불능으로 만듭니다. fcntl.fnctl() stdin의 파일 기술자 깃발을 획득하고 그것들을 비-블로킹(non-blocking) 모드로 변경하는데 사용됩니다. 비어있을 때 stdin을 읽는 것은 IOError를 일으키므로, 이 에러는 나포되고 무시됩니다.


4.95. 펄의 chomp()와 동등한 것이 있나요? (문자열에서 끌리는 newline을 제거하는 것)

두 개의 부분적인 대안이 있습니다. 만약 모든 이끌리는 공백을 제거하려면, 메쏘드 string.rstrip()을 사용하세요. 그렇지 않고, 그 문자열에 오직 한개의 라인만 있다면, string.splitlines()[0]을 사용하세요.

 -----------------------------------------------------------------------
 rstrip()은 너무 욕심이 많아서, 모든 이끌리는 공백들을 제거합니다.
 splitlines()는 ControlM을 라인 경계값으로 취합니다.
 이 문자열들을 입력이라고 간주해 보면:
   "python python    \r\n"
   "python\rpython\r\n"
   "python python   \r\r\r\n"
 rstrip()/splitlines()으로부터 돌아온 결과는 아마도 우리가 원한 것이 아닐 것입니다.
 보기에는 re가 이 작업을 수행할 수 있는 것 같습니다.

 #!/usr/bin/python
 # requires python2
 import re, os, StringIO
 lines=StringIO.StringIO(
   "The Python Programming Language\r\n"
   "The Python Programming Language \r \r \r\r\n"
   "The\rProgramming\rLanguage\r\n"
   "The\rProgramming\rLanguage\r\r\r\r\n"
   "The\r\rProgramming\r\rLanguage\r\r\r\r\n"
 )
 ln=re.compile("(?:[\r]?\n|\r)$") # dos:\r\n, unix:\n, mac:\r, others
: unknown
 # os.linesep does not work if someone ftps(in binary mode) a dos/mac text file
 # to your unix box
 #ln=re.compile(os.linesep + "$")
 while 1:
   s=lines.readline()
   if not s: break
   print "1.(%s)" % `s.rstrip()`
   print "2.(%s)" % `ln.sub( "", s, 1)`
   print "3.(%s)" % `s.splitlines()[0]`
   print "4.(%s)" % `s.splitlines()`
   print
 lines.close()


4.96. (리스트, 터플, 연속열)의 요소들을 실제로 결합할 때 join()은 왜 문자열 메쏘드인가요?

문자열은 배포본 1.6부터는 다른 표준 형들과 거의 같게 되었습니다, 메쏘드는 추가되어 string 모듈의 기능을 사용하여 언제나 이용가능하던 기능과 동일한 기능을 제공합니다. 이러한 새로운 메쏘드는 광범위하게 받아들여졌습니다, 그러나 (어떤) 프로그래머들을 불편하게 느끼게 만드는 것이라면:

    ", ".join([1, 2, 4, 8, 16])
이것은 다음의 결과를 산출합니다

    "1, 2, 4, 8, 16"
이러한 사용법에 대해서는 두 개의 일반적인 반론이 있습니다.

그 첫 번째는 다음 라인에 읽혀지는 대로 입니다: "문자열 기호 (문자열 상수)의 메쏘드를 사용하는 것은 정말 보기에 흉하다", 이것에 대한 대답은 다음과 같습니다. 그럴 수도 있지만, 문자열 기호는 단지 고정된 값입니다. 만약 그 메쏘드들이 문자열에 엮여진 이름들에 허용된다면 기호상으로 불가능하게 해야 할 논리적인 이유가 없습니다. 넘어야할 산입니다!

두 번째 반대는 전형적으로 다음과 같이 던져집니다: "나는 연속열이 그의 구성원들을 문자열 상수와 함께 결합하기를 진정으로 바란다." 슬프게도, 그럴 수 없습니다. 어떤 이유 때문에 split()을 문자열 메쏘드로 간주하는데에는 큰 어려움이 없어 보입니다, 왜냐하면 이 경우에 다음은

    "1, 2, 4, 8, 16".split(", ")
주어진 구분자에 의해서 구분된 하부문자열을 문자열 기호에게 반환하라는 지시라고 이해하는 것이 쉽습니다 (혹은, 기본값으로, 임의의 수행은 공백). 이 경우에 유니코드 문자열은 유니코드 문자열을 담은 리스트를 반환하고, 아스키 문자열을 아스키 문자열을 담은 리스트를 반환하고 그리고 모든 사람은 행복합니다.

join()은 문자열 메쏘드입니다. 왜냐하면 그것을 사용하고 있는 동안에 임의의 연속열에 대하여 그 구분 문자열이 반복되도록 지시하고, 각 요소의 문자열 표현을 형성하며, 그리고 자신을 그 요소들의 표현 사이에 삽입하고 있기 때문입니다. 이 메쏘드는 연속열 객체를 위한 규칙을 준수하는 모든 인수와 함께 사용될 수 있습니다, 여기에는 스스로 정의한 새로운 클래스를 포함됩니다.

이것은 문자열 메쏘드이므로 유니코드 문자열 뿐만 아니라 평문 아스키 문자열에도 작동할 수 있습니다. 만약 join()이 그 연속열 형의 메쏘드라면 그 연속열 형은 구분자의 형에 따라서 어떤 형의 문자열을 반환해야 할지를 결정해야만 할 것입니다.

이러한 주장들에 대하여 만족하지 못하면, 현재로는 계속하여 string 모듈에 있는 join() 함수를 사용할 수 있습니다, 이것으로 다음과 같이 작성할 수 있습니다

    string.join([1, 2, 4, 8, 16], ", ")
모듈은 실제로 불평하고 있는 그 구문을 사용해서 선호하는 구문을 구현한다는 것을 잊어버리려고 노력해야 할 것입니다!


4.97. 어떻게 나의 코드가 한 객체의 이름을 알아낼 수 있습니까?

일반적으로 말해서, 그럴 수 없습니다, 왜냐하면 객체는 실제로는 이름을 가지지 않기 때문입니다. 할당 서술문은 할당된 값을 그 이름에 저장하는 것이 아니라 그것에 대한 참조점을 저장합니다. 필수적으로, 할당은 값에 대한 이름의 엮기를 생성합니다. 같은 진리가 defclass 서술문에도 적용됩니다, 그러나 그 경우에는 그 값이 호출가능합니다. 다음의 코드를 연구해 보세요:

    class A:
        pass
    B = A
    a = B()
    b = a
    print b
    <__main__.A instance at 016D07CC>
    print a
    <__main__.A instance at 016D07CC>

의도적으로 이 클래스는 이름을 가집니다: 두 개의 이름에 엮여져 있고 이름 B 를 통하여 호출됨에도 불구하고, 생성된 실체는 여전히 클래스 A의 실체로 보고 되고 있습니다. 그렇지만, 그 실체의 이름이 a 인지 b 인지는 말할 수 있는데, 두 이름 모두 같은 값에 엮여 있기 때문입니다.

일반적으로 이야기 해서 여러분의 코드가 특정한 값의 "이름을 알아야 할" 필요는 없습니다. 의도적으로 내부를 들여다 보는 프로그램을 만들고 있지 않다면, 이것은 보통 접근법을 바꾸어 보는 것이 유익한다는 것을 나타내 주고 있습니다.


4.98. 왜 부동 소수점수 계산은 그렇게 부정확한가요?

[8-Aug-2001: 파이썬 지도서의 개발 버전은 이제 부록에 다음과 같은 더 많은 정보를 포함하고 있습니다:
    http://python.sourceforge.net/devel-docs/tut/node14.html
]

사람들은 가끔 다음과 같은 결과에 매우 놀랍니다:

 >>> 1.2-1.0
 0.199999999999999996
그리고 파이썬의 버그라고 생각합니다. 그렇지 않습니다. 그것은 부동 소수점수의 내부 표현 때문에 야기된 문제입니다. 부동 소수점수는 고정된 개수의 이진 자리수로 저장됩니다.

10진수에서는, 고정된 개수의 십진 자리수로 표현될 수 없는 숫자들이 많습니다, 즉, 1/3 = 0.3333333333.......

이진 수의 경우에는, 1/2 = 0.1, 1/4 = 0.01, 1/8 = 0.001, 등등 표현될 수 없는 숫자들이 많습니다. 지리수는 어떤 점에서 절단됩니다.

파이썬 1.6 이후로, 부동 소수점의 repr() 함수는 임의의 실수 f에 대하여 eval(repr(f)) == f를 참으로 만드는데 필요한 만큼의 자리수를 출력합니다. str() 함수는 아마도 원한바의 더욱 의미 있는 숫자를 출력합니다:

 >>> 0.2
 0.20000000000000001
 >>> print 0.2
 0.2
또 다시, 이것은 파이썬과 관련이 없습니다, 그러나 C 플랫폼이 기저에서 부동소수점수를 다루는 방식과 관련이 있으며, 궁극적으로는 고정된 개수의 수치 문자열을 써낼 때 항상 가지게 되는 부정확성과 관련이 있습니다.

이 결과중의 하나는 계산의 결과를 ==으로 실수형과 비교하는 것은 위험하다는 것입니다! 약간만 부정확해도 == 는 실패한다는 것을 의미합니다.

대신에 다음과 같은 것을 시도해 보세요:

 epsilon = 0.0000000000001 # Tiny allowed error
 expected_result = 0.4
 if expected_result-epsilon <= computation() <= expected_result
+epsilon:
    ...


4.99. 버클리 DB 파일을 열어 보려고 했지만, bsddb는 bsddb.error를 발생시킵니다: (22, 'Invalid argument'). 도와주세요! 어떻게 해야 나의 데이타를 복구할 수 있을까요?

당황하지 마세요! 데이타는 아마도 그대로일 것입니다. 그 에러에 대한 가장 흔한 이유는 이전의 버클리 DB 파일을 이후의 버클리 DB 라이브러리 버전으로 열려고 시도한 것입니다.

많은 리눅스 시스템은 이제 세개의 버클리 DB 버전 모두 이용가능합니다. 만약 버전 1 에서 새로운 버전으로 옮길 생각이라면 db_dump185를 사용하여 그 데이타 베이스의 평문 텍스트 버전을 덤프하세요. 만약 버전 2 에서 버전 3으로 이동할 생각이라면 db2_dump를 사용하여 그 데이타 베이스의 평문 텍스트 버전을 생성하세요. 어느 경우에나, db_load를 사용하여 컴퓨터에 설치된 최신 버전용으로 고유한 데이타베이스를 새롭게 생성하세요. 만약 버전 3 의 버클리 DB가 설치되어 있다면, db2_load를 사용하여 버전 3용 고유한 데이타베이스를 생성하실 수 있을 것입니다.

해쉬 파일 코드가 데이타를 망가트릴수 있다고 알려진 버그를 포함하고 있기 때문에 버클리 DB 버전 1 파일로부터 이동하셔야 할 것입니다.


4.100. 어떤 것이 모듈에서 import를 사용하는 "가장 좋은 관습(best practices)"인가요?

먼저, 표준 모듈은 훌륭합니다. 그것을 사용하세요! 표준 파이선 라이브러리는 거대하고 다양합니다. 모듈을 사용하면 시간과 노력을 절감할 수 있으며 코드의 유지 보수 비용을 감소 시켜 줄 것입니다. (다른 많은 프로그램들이 표준 파이썬 모듈에 있는 버그들을 수정하고 지원하는데 공헌하고 있습니다. 협력자들은 또한 여러분이 사용하는 그 모듈들에 익숙하기 때문에, 여러분의 코드를 이해하는데 걸리는 시간의 양을 감소시켜 줄 것입니다.)

이 대답의 나머지는 대부분 개인적 선호도의 문제입니다, 그러나 여기에 어떤 뉴스그룹의 필자가 말한 것이 있습니다 (응답해준 모든 분에게 감사드립니다)

일반적으로, 다음과 같이 사용하지 마세요

 from modulename import *
그렇게 하면 수입자의 이름공간이 어지럽혀집니다. 어떤 사람들은 이런방식으로 수입되도록 디자인된 모듈에서 조차 이런 관용법을 피합니다. (이런 방식으로 디자인된 모듈에는 Tkinter, thread, 그리고 wxPython이 포함됩니다.)

파일의 상단에 모듈들을, 한 줄에 한 모듈씩 수입하세요. 그렇게 하면 코드가 어떤 모듈을 필요로 하는지 명확히 할 수 있으며 그 모듈의 이름이 영역안에 존재하는지 어떤지의 문제를 피할 수 있습니다.

만약 많은 수입들이 있고, 그리고 그 비용 ( 많은 초기화 시간)을 피하고자 한다면. 수입들을 (함수 정의의 최상단과 같은) 지역 영역 안으로 이동시키세요. 이 테크닉은 그 프로그램이 어떻게 실행되느냐에 따라서 많은 수입이 불필요할 때 특히 유용합니다. 만약 그 모듈이 단지 그 함수에서만 사용된다면 수입을 함수 안으로 이동시키고 싶을 수도 있습니다. (그 모듈을 초기화하는 시간 때문에) 처음으로 모듈을 적재할 때는 비싼대가를 치를 수도 있습니다 그러나 모듈을 여러번 적재하는 것은 실제적으로 무료입니다 (많은 수의 사전 참조). 그 모듈 이름이 영역 밖으로 나갔을 지라도, 그 모듈은 sys.modules에서 사용가능합니다. 그리하여, 모듈 수준에 (필요하지 않다면) 수입을 배정하지 않고 함수 수준에 모든 수입을 배정해도 실제적으로 아무런 문제가 없습니다.

어떤 경우에는 필수적으로 수입을 함수 혹은 클래스로 이동시켜서 순환 수입의 문제를 피해야 합니다. 고든(Gordon)은 다음과 같이 말합니다:

 순환 수입은 두 모듈 모두 "import <module>" 형태의 수입을 사용하는 곳에서 훌륭합니다. 
 순환수입은 두 번째 모듈이 첫 번째 모듈로부터 이름을 얻으려고 할 때 ("from module import name") 
 그리고 수입이 최상위 수준에 있을 때 실패합니다.
 그것은 첫 번째 모듈에 있는 이름들이 아직 사용가능하지 않기 때문입니다,
 (첫 번째 모듈은 두 번째 모듈을 수입하느라 바쁩니다).
이 경우에, 만약 두 번째 모듈이 오직 하나의 함수에서만 사용된다면, 수입은 쉽게 그 함수안으로 이동될 수 있습니다. 그 수입이 호출될 때 까지는, 첫 번째 모듈은 초기화를 완결할 것이며, 그리고 두 번째 모듈은 수입을 할 수 있습니다.

어떤 모듈들이 플랫폼-종속적이라면 최상위 수준의 코드로부터 수입을 이동시킬 필요가 있을지도 모릅니다. 그 경우에, 그 파일의 최상위에서 모든 모듈을 수입하는 것조차도 불가능할지도 모릅니다. 이 경우에는, 정확한 모듈을 상응하는 플랫폼-종속적 코드에서 수입하는 것이 훌륭한 선택입니다.

만약 특정 클래스의 실체들만이 모듈을 사용한다면, 모듈을 그 클래스의 __init__ 메쏘드에서 수입하고 그 모듈을 실체 변수에 할당하여서 그 객체가 살아 있는 동안에 항상 (그 실체 변수를 통하여) 사용가능하도록 하는 것이 현명합니다. 주목할 것은 그 클래스가 실체화 될 때까지 수입을 연기하려면, 그 수입은 반드시 메쏘드 안에 있어야 한다는 것입니다. 수입을 그 클래스 안이기는 하지만 메쏘드의 밖에 배정하는 것은 그 모듈이 초기화 될 때 여전히 그 수입이 일어나도록 야기합니다.


4.101. 버그를 찾아내거나 정적인 분석을 도와주는 도구가 있나요?

네. PyChecker는 정적 분석 도구로서 파이썬 소스코드에 있는 버그를 찾아낼 뿐만 아니라 코드의 복잡성과 스타일에 관해서도 경고해 줍니다.

PyChecker는 다음에서 : http://pychecker.sf.net/ 얻을 수 있습니다.


4.102. UnicodeError: ASCII decoding error: ordinal not in range(128) *

이 에러는 설치된 파이썬이 오직 7-비트 아스키 코드만을 다룰 수 있다는 것을 나타냅니다. 걱정하지 마세요, 쉽게 고칠 수 있으며 쉽게 파이썬이 정 8-비트 코드전환을 사용할 수 있습니다.

이 문제를 해결하는 가장 간결한 방법은 site.py를 편집하는 것입니다. 거기, 마지막 부분에서, 다음과 같은 라인을 발견할 것입니다

    encoding = "ascii"
"ascii"를 여러분이 원하는 코드전환으로 변경하세요. 주의깊게 site.py 모듈에 있는 다음의 라인을 읽어 보시면, 거기에서 "if 0:"으로 주석처리된 라인들을 발견할 수 있을 것입니다. 이 라인의 주석을 제거하시면 파이썬은 현재의 로케일 설정값을 (LC_CTYPE 환경 변수, 또는 LANG/LC_ALL) 사용하여 선호하는 코드 전환을 결정할 것입니다.

그리고 마지막으로, sitecustomize.py를 만들 수 있는데, 여러분이 원하는 방식으로 코드전환을 설정해 줄 것입니다. 나는 그러한 라인이 주석제거되어 수정된 site.py 버전을 사용합니다.

    # Set the string encoding used by the Unicode implementation.
    # The default is 'ascii'
    encoding = "ascii" # <= CHANGE THIS if you wish
    # Enable to support locale aware default string encodings.
    import locale
    loc = locale.getdefaultlocale()
    if loc[1]:
        encoding = loc[1]
    if encoding != "ascii":
        import sys
        sys.setdefaultencoding(encoding)

또한 윈도우에서 주의할 것은, "mbcs"라고 알려진 코드전환이 있는데, 현재의 로케일에 종속적인 코드 전환을 사용합니다. 많은 경우에, 특히 COM과 작동할 때는, 이것이 아마도 사용해야할 적절한 기본 코드전환이 될 것입니다.


앞으로    목차    1    2    3    제4장    5    6    7    8    다음으로