서 문 목 차 제 2 장 검사의 힘 >>

제 1 장. 파이썬을 알아보기

1.1. 다이빙해 들어가기

다음 파이썬 프로그램은 완전하게 작동한다.

이해가 잘 안가실지도 모르겠지만, 걱정할 필요가 없다; 한줄 한줄 분해해 보겠다. 그러나 먼저 훓어보고, 무엇을 이해했는지 알아보자.

Example 1.1. odbchelper.py

아직 그렇게 하지 못했다면, 이 예제와 더불어 이 책에서 사용되는 다른 예제들을 모두 내려 받을 수 있다 (Windows, UNIX, Mac OS).

def buildConnectionString(params):
    """Build a connection string from a dictionary of parameters.

    Returns string."""
    return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

if __name__ == "__main__":
    myParams = {"server":"mpilgrim", \
                "database":"master", \
                "uid":"sa", \
                "pwd":"secret" \
                }
    print buildConnectionString(myParams)

이제 이 프로그램을 실행시키고 무슨 일이 일어나는지 보자.

Tip
윈도우즈의 파이썬 IDE라면 모듈을 File->Run... (Ctrl-R)으로 실행할 수 있다. 출력은 대화형 창에 나타내어진다.
Tip
맥 운영체제의 파이썬 IDE 에서는 모듈을 Python->Run window... (Cmd-R)으로 실행할 수 있다. 그러나 거기에는 먼저 설정해야할 중요한 선택사항이 있다. IDE에서 모듈을 열고, 창의 우-상 모서리에 있는 검은 삼각형을 클릭해서 모듈의 선택사항을 띄워라. 그리고 “Run as __main__” 이 체크되어 있나 확인하라. 이 설정은 그 모듈에 저장되기 때문에, 각 모듈에 대하여 한 번만 이렇게 해 주면 된다.
Tip
(맥 OS X 를 포함하여) 유닉스 호환 시스템이라면 모듈을 명령어 라인으로부터 실행할 수 있다: python odbchelper.py

Example 1.2. Output of odbchelper.py

server=mpilgrim;uid=sa;database=master;pwd=secret

1.2. 함수를 선언하기

파이썬은 다른 대부분의 언어들과 마찬가지로 함수를 가지고 있다. 그러나 C++ 과 같이 따로 헤더 파일이 없으며, 파스칼과 같이 interface/implementation와 같은 섹션이 없다. 함수가 필요하다면, 그냥 함수를 선언하고, 코드를 작성하면 된다.

Example 1.3. Declaring the buildConnectionString function

def buildConnectionString(params):

여기서 주목할 몇가지가 있다면, 첫째 def 키워드로 함수의 정의를 시작하며, 뒤이어서 함수의 이름이 따르고, 그 뒤에는 괄호로 둘러싸인 인자가 온다. (여기서 보여지지 않은) 다중 인자는 콤마로 분리한다.

둘째로, 함수는 반환 데이타의 형을 정의하지 않는다. 파이썬 함수는 반환 값에 데이타형을 지정하지 않는다; 심지어 값을 반환하는지 안 하는지도 지정하지 않는다. 사실 모든 파이썬 함수들은 값을 반환한다; 함수가 return 서술문을 실행한다면, 함수는 값을 반환할 것이다, 그렇지 않으면 파이썬의 null값인 None을 반환할 것이다.

Note
비쥬얼 베이직에서, (값을 반환하는) 함수는 function으로 시작하고, 그리고 (값을 반환하지 않는) 서브루틴은 sub 로 시작한다. 파이썬에는 서브루틴이 없다. 모든 것은 함수이고, (심지어 그 값이 None일지라도) 모든 함수는 값을 반환한다. 그리고 모든 함수는 def 로 시작한다.

셋째로, 인자 params는 데이타형을 지정하지 않는다. 파이썬에서 변수들은 명시적으로 유형이 정의되지 않는다. 파이썬은 변수가 어떤 형인지를 이해하고 내부적으로 기록 유지한다.

Note
자바, C++, 그리고 기타 강력-형정의 언어에서는 함수의 반환값에 데이타 형과 각 함수의 인자들에 데이타 형을 지정해야만 한다. 파이썬에서는 명시적으로 어떤 데이타형도 지정하지 않는다. 어떤 값을 할당했느냐에 따라서 그 데이타의 형을 내부적으로 기록 유지한다.

1.3. 함수를 문서화하기

파이썬 함수에 doc string를 제공함으로써 문서화 할 수 있다.

Example 1.4. Defining the buildConnectionString function's doc string

def buildConnectionString(params):
    """Build a connection string from a dictionary of parameters.

    Returns string."""

세개짜리 인용부호는 여러-줄 문자열을 의미한다. 인용부호의 처음과 마지막 사이에 있는 모든 것은 나르개 복귀 문자 그리고 기타 인용부호 문자들을 포함하여, 하나의 문자열이다. 어느 곳에나 마음대로 사용할 수 있지만, 대부분의 사용처는 doc string을 정의할 때이다.

Note
세개짜리 인용부호는 홑따옴표 그리고 겹따옴표로 하나의 문자열을 펄에서의 qq/.../와 같이 정의하기 쉽게 해준다.

세개짜리 인용부호 사이에 있는 모든 것은 함수의 문서화 문자열(doc string)로서 그 함수가 무엇을 하는지 문서화 한다. doc string은 반드시 한 함수에서 가장 먼저 정의되어야 한다 (즉, 쌍점 다음 가장 첫 번째의 것). 기술적으로 함수에 문서화 문자열(doc string)은 필요없지만, 항상 달아 두는 것이 좋다. 이 충고를 그 동안 받았던 모든 프로그래밍 수업에서 지겹게 들어보았으리라고 생각한다. 하지만, 파이썬에는 여러분이 그렇게 해야할 동기가 제공된다: doc string은 실행시에 그 함수의 속성으로 사용가능하다.

Note
많은 파이썬 IDE들은 doc string을 사용하여 문맥-감지 문서화를 제공하며, 그래서 한 함수의 이름을 타자하면, doc string이 풍선도움말로 나타난다. 이것은 대단히 도움을 주지만, 여러분이 doc string을 작성했을 때만이 유효하다.

더 읽어야 할 것

1.4. 모든 것은 객체이다

이 말을 이해 못하겠다면, 단지 이렇게 말해 주겠다. 파이썬의 함수는 속성들을 가지며, 그러한 속성들은 실행시에 사용가능하다고 말이다.

파이썬의 다른 어떤 것들과 마찬가지로, 함수는 객체이다.

Example 1.5. Accessing the buildConnectionString function's doc string

>>> import odbchelper                              1
>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> print odbchelper.buildConnectionString(params) 2
server=mpilgrim;uid=sa;database=master;pwd=secret
>>> print odbchelper.buildConnectionString.__doc__ 3
Build a connection string from a dictionary
Returns string.
1 첫 줄은 odbchelper 프로그램을 모듈로 반입한다. 모듈을 반입하면, 그 모듈의 공개 함수, 클래스, 혹은 속성들 중 어느 것이라도 참조할 수 있다. 모듈은 이렇게 하여 다른 모듈의 기능에 접근할 수 있으며, 그것을 IDE에서도 역시 사용할 수 있다. 이것은 중요한 개념으로서 나중에 그것을 더욱 자세히 논의하겠다.
2 반입된 모듈에 정의된 함수를 사용하고 싶다면, 모듈이름을 포함해야만 한다. 그래서 단지 buildConnectionString 이라고 말하는 것으로는 부족하고, odbchelper.buildConnectionString이라고 해야 한다. 자바에서 클래스를 사용해 보았다면, 대단히 친숙하게 느껴질 것이다.
3 예상했던 함수를 호출하는 대신에, 함수의 속성중 하나인 __doc__를 요구했다.
Note
파이썬의 import는 펄에서의 require와 비슷하다. 파이썬 모듈을 반입하면, 그 모듈의 함수에 module.function형태로 접근할 수 있다; 펄 모듈을 요구(require)하면, 그 모듈의 함수에 module::function의 형태로 접근하듯이 말이다.

파이썬에서 모든 것은 객체이다. 그리고 거의 모든 것은 속성과 메쏘드를 가진다. [1] 모든 함수들은 내장 속성인 __doc__을 가지며, 그 함수의 소스 코드에서 정의된 문서화 문자열(doc string)을 반환한다.

이것은 너무 중요하기 때문에 잊어 버릴 경우를 대비해서 몇 번이고 반복해서 상기시켜 주겠다: 파이썬에서 모든 것은 객체이다. 스트링은 객체이다. 리스트는 객체이다. 함수는 객체이다. 심지어는 모듈도 객체이다. 간단하게 살펴보겠다.

더 읽어야 할 것

1.5. 코드를 들여쓰기

파이썬 함수는 명시적으로 begin 혹은 end를 전혀 가지지 않으며, 함수가 시작하고 끝나는 지점을 표시해주는 아무런 활괄호도 가지지 않는다. 유일한 식별자는 쌍점(“:”)이며 코드의 들여쓰기 그 자체이다.

Example 1.6. Indenting the buildConnectionString function

def buildConnectionString(params):
    """Build a connection string from a dictionary of parameters.
    Returns string."""
    return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

코드 블록들 (함수, if 서술문, for 회돌이, 등등)은 들여쓰기로 정의된다. 들여쓰기는 한 블록의 시작을 의미하며 들여쓰기를 원래대로 환원하면 블록이 끝난다; 명시적으로 괄호, 각괄호, 혹은 키워드가 없다. 이것은 공백이 중요하며, 그리고 일관성이 있어야 한다는 것을 뜻한다. 이 예제에서 함수 코드는 ( doc string을 포함하여) 4개의 공백으로 들여쓰기 된다. 반드시 4가 되어야 할 필요는 없고, 단지 일관성만 있으면 된다. 들여쓰기 되지 않은 첫 번째 줄은 함수의 바깥에 있다.

초기에 약간의 저항이 따르고 포트란과 비교하여 약간의 고난을 겪고나면 이것에 익숙해질 것이며 그 이점들을 보기 시작할 것이다. 가장 커다란 이점은 모든 파이썬 프로그램들은 비슷하게 보인다라는 것이다. 왜냐하면 들여쓰기는 언어의 필수조건이며 스타일의 문제가 아니기 때문이다. 이것으로 다른 사람들의 파이썬 코드를 더 쉽게 읽고 이해할 수 있다.

Note
파이썬은 나르개 복귀 문자를 사용하여 서술문을 분리하고 쌍점과 들여쓰기를 사용하여 코드 블록을 분리한다.

더 읽어야 할 것

1.6. 모듈을 테스트하기

파이썬 모듈은 객체이며 유용한 속성들을 가진다. 모듈을 작성할 때 이 속성들을 사용하여 쉽게 모듈을 테스트할 수 있다.

Example 1.7. The if __name__ trick

if __name__ == "__main__":

이 멋진 재료를 다루어 보기 전에 먼저 약간 살펴볼 것이 있다. 괄호는 if 표현식 주위에 필요하지 않다. 두 번째, if 서술문은 콜론으로 끝난다. 그리고 뒤에 들여쓰기된 코드가 따른다.

Note
C 와 같이, 파이썬은 == 을 비교를 위해 사용하고 =를 할당을 위해 사용한다. C 와는 다르게 파이썬은 in-line 할당을 제공하지 않는다. 그래서 여러분이 비교하고 있다고 생각하는 값을 실수로 할당할 일은 없다.

그러면 왜 이러한 특이한 if 서술문이 꼼수인가? 모듈은 객체이다. 그리고 모든 모듈은 내장 속성인 __name__을 가지고 있다. 한 모듈의 __name__은 그 모듈을 어떻게 이용하느냐에 달려 있다. 모듈을 반입하면, __name__은 그 모듈의 파일이름이며, 디렉토리 경로 혹은 파일 확장자는 없다. 그러나 그 모듈을 독립적인 프로그램으로 직접 실행시킬 수 있는데, 그 경우에 __name__은 특별한 기본 값으로 __main__이 된다.

Example 1.8. An imported module's __name__

>>> import odbchelper
>>> odbchelper.__name__
'odbchelper'

이 사실을을 알고 나면 이러한 if 서술문에 모듈을 배치함으로써 모듈 자체 안에서 그 모듈을 위한 테스트 모둠을 디자인할 수 있다. 모듈을 직접적으로 실행하면, __name____main__이 되고, 그래서 테스트 모둠은 실행된다. 모듈을 반입하면, __name__은 다른 어떤 이름이 되고, 그래서 테스트 모둠은 무시된다. 이 때문에 새로운 모듈을 더 쉽게 개발하고 디버그한 다음 더 큰 프로그램으로 통합할 수 있다.

Tip
맥 파이썬에서는 if __name__ 꼼수를 작동시키기 위해서 단계가 하나 더 있다. 창의 우-상 모서리에 있는 검정색 삼각형을 클릭함으로써 모듈의 선택사항 메뉴를 띄워라, 그리고 확실히 __main__ 이 체크된 상태로 실행하라.

더 읽어야 할 것

1.7. 사 전 101

잠깐 샛길로 빠져보자. 왜냐하면 사전, 터플, 그리고 리스트에 관하여 알 필요가 있기 때문이다(오 세상에 이게 샛길이라니!). 여러분이 펄 해커라면, 아마도 사전과 리스트에 관한 정도는 슬쩍 넘겨 버릴 수도 있겠지만, 여전히 터플에 관하여 주의를 기울여야만 한다.

파이썬의 내장 데이타형 중의 하나는 사전이다. 사전은 키와 값들 사이의 관계를 일대일로 정의한다.

Note
파이썬의 사전은 펄의 해쉬와 비슷하다. 펄에서 해쉬를 저장하고 있는 변수들은 항상 % 문자로 시작한다; 파이썬에서 변수는 마음대로 이름을 지을 수 있고, 데이타형을 내부적으로 기록 유지한다.
Note
파이썬에서 사전은 자바에 있는 Hashtable 클래스의 실체와 비슷하다.
Note
파이썬의 사전은 비쥬얼 베이직에 있는 Scripting.Dictionary 객체의 실체와 비슷하다.

Example 1.9. Defining a dictionary

>>> d = {"server":"mpilgrim", "database":"master"} 1
>>> d
{'server': 'mpilgrim', 'database': 'master'}
>>> d["server"]                                    2
'mpilgrim'
>>> d["database"]                                  3
'master'
>>> d["mpilgrim"]                                  4
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
KeyError: mpilgrim
1 먼저 새로운 사전을 두 개의 요소로 만들고 그것을 변수 'd'에다 할당한다. 각 요소는 키-값 쌍이며, 요소의 모든 모둠은 활괄호에 의해 둘러 싸여진다.
2 server 는 키이고, 그리고 d["server"]가 참조하는 그것과 연관된 값은 mpilgrim이다.
3 database 는 키이고, d["database"]가 참조하는 그것과 연관된 값은 master이다.
4 키로 값을 획득할 수 있지만 값으로 키를 얻을 수는 없다. 그래서 d["server"]mpilgrim이지만, d["mpilgrim"]은 예외를 일으킨다. 왜냐하면 mpilgrim 은 키가 아니기 때문이다.

Example 1.10. Modifying a dictionary

>>> d
{'server': 'mpilgrim', 'database': 'master'}
>>> d["database"] = "pubs" 1
>>> d
{'server': 'mpilgrim', 'database': 'pubs'}
>>> d["uid"] = "sa"        2
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'pubs'}
1 하나의 사전에서 키를 중복해서 가질수는 없다. 하나의 값을 존재하는 키에 할당하면 예전 값은 사라진다.
2 새로운 키-값쌍을 언제든지 추가할 수 있다. 이러한 구문은 존재하는 값들을 변경하는 것과 동일하다. (사실 이 때문에 언젠가는 짜증이 날 때가 있을 것이다. 새로운 값을 추가하고 있다고 생각했지만 실제로는 단순히 같은 값을 변경하고 또 변경하는 것에 불과할 때가 있을 텐데 왜냐하면 키는 예상대로 변하지 않기 때문이다.)

주목할 것은 새로운 요소 (key uid, value sa)가 중앙에 나타난다는 것이다. 사실 요소들이 첫 번째 예제에서 순서대로 나타난 것은 단순한 우연의 일치였을 뿐이다; 지금은 순서대로 나타나지 않은 것도 단순히 똑 같은 우연의 일치이다.

Note
사전은 요소들 사이에 순서의 개념을 전혀 가지지 않는다. 요소들이 “무질서 하다”라고 말하는 것도 부정확하다; 단순히 순서가 없을 뿐이다. 이것은 중요한 구별로서 사전에 있는 요소들에 특별한, 반복적인 순서로 (키에 의한 알파벳 순서로) 접근하려고 할때 신경이 쓰일 것이다. 이렇게 하는 방법은 여러가지가 있는데, 단순히 사전으로 구축되어 들어가지 않는다.

Example 1.11. Mixing datatypes in a dictionary

>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'pubs'}
>>> d["retrycount"] = 3 1
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3}
>>> d[42] = "douglas"   2
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 42: 'douglas', 'retrycount': 3}
1 사전은 문자열만을 위한 것은 아니다. 사전의 값은 어떤 데이타형도 될 수 있다. 문자열, 정수, 객체, 심지어 다른 사전까지도 가능하다. 하나의 사전안에서 값들이 모두 같은 유형일 필요가 없다; 마음대로 혼합하고 짝지을 수 있다.
2 사전의 키들은 더욱 제한적이다. 그러나, 문자열, 정수, 그리고 다른 어떤 형들 (이것에 관하여는 나중에 더 자세히 다룸)이 될 수 있다. 하나의 사전안에서 키의 데이타 형을 혼용하고 짝지을 수도 있다.

Example 1.12. Deleting items from a dictionary

>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 42: 'douglas', 'retrycount': 3}
>>> del d[42] 1
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3}
>>> d.clear() 2
>>> d
{}
1 del 으로 사전으로부터 키 값으로 항목들을 따로따로 삭제할 수 있다.
2 clear 은 사전으로부터 모든 항목을 삭제한다. 주의할 것은 빈 활괄호의 집합은 아무런 요소도 없는 사전을 의미한다는 것이다.

더 읽어야 할 것

1.8. 리스트 101

리스트는 파이썬의 주요 데이타형이다. 리스트에 대한 유일한 경험이 비쥬얼 베이직에서의 배열 혹은 파워빌더에서의 데이타스토어라면, 파이썬의 리스트에 대하여 단단히 준비하라.

Note
파이썬의 리스트는 펄의 배열과 비슷하다. 펄에서 배열을 저장하는 변수는 항상 @ 문자로 시작한다; 파이썬에서 변수는 어떤 이름이라도 될 수 있으며, 파이썬은 데이타형을 내부적으로 기록유지한다.
Note
(평생동안 리스트만 쓸 생각이라면 리스트를 배열처럼 사용할 수도 있겠지만) 파이썬의 리스트는 자바에서의 배열 그 이상이다). 훨씬 좋은 비유를 들자면 Vector 클래스일텐데, 이 클래스는 임의적인 객체들을 보유할 수 있고 새로운 항목이 추가될 때마다 동적으로 확장할 수 있다.

Example 1.13. Defining a list

>>> li = ["a", "b", "mpilgrim", "z", "example"] 1
>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[0]                                       2
'a'
>>> li[4]                                       3
'example'
1 먼저, 5개의 요소를 가지는 리스트를 정의한다. 자신의 원래 순서를 유지하고 있는 것을 주목하자. 이것은 우연히 일어난 일이 아니다. 리스트는 각괄호에 의해 둘러싸여진 요소들로 구성된 순서가 있는 집합이다.
2 리스트는 기본첨자가 0인 배열처럼 사용될 수 있다. 비어있지 않는 모든 리스트의 첫번째 요소는 항상 li[0] 이다.
3 이 5개의 리스트에 있는 마지막 요소는 li[4]인데, 왜냐하면 리스트는 항상 0에서 시작하기 때문이다.

Example 1.14. Negative list indices

>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[-1] 1
'example'
>>> li[-3] 2
'mpilgrim'
1 음수 지표는 요소들을 리스트의 끝으로부터 거꾸로 세어서 접근한다. 비어있지 않은 모든 리스트의 마지막 요소는 항상 li[-1]이다.
2 만약 음의 지표가 혼란스럽다면, 다음 방식을 고려해 보라: li[n] == li[n - len(li)]. 그래서 이 리스트에서, li[2] == li[2 - 5] == li[-3] 이다.

Example 1.15. Slicing a list

>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[1:3]  1
['b', 'mpilgrim']
>>> li[1:-1] 2
['b', 'mpilgrim', 'z']
>>> li[0:3]  3
['a', 'b', 'mpilgrim']
1 2개의 지표를 지정함으로써 리스트의 하부 집합을 얻을 수 있는데, 이를 “조각썰기(slice)”라고 부른다. 반환값은 순서대로, 첫번째 썰기 지표 (이 경우에는 li[1])에서 시작하여, 두번째 썰기 지표(이 경우에는 li[3])까지 (이 값은 포함하지 않음) 그 리스트의 모든 요소들을 포함하는 새로운 리스트이다.
2 썰기 지표가 둘 혹은 하나가 음수일지라도 썰기는 작동한다. 이런식으로 생각하면 도움이 될지 모르겠다: "리스트를 왼쪽에서 오른쪽으로 읽어가면서, 첫 번째 썰기 지표는 원하는 첫 번째 요소를 지정하는 것이며, 그리고 두번째 지표는 원하지 않는 첫 번째 요소를 지정한다"고 말이다. 반환값은 그 사이의 모든 것이다.
3 리스트는 0에서 첨자가 시작된다. 그래서 li[0:3]은 리스트의 첫번째 3개의 요소를, li[0]이상 li[3]미만으로 반환한다.

Example 1.16. Slicing shorthand

>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[:3] 1
['a', 'b', 'mpilgrim']
>>> li[3:] 2
['z', 'example']
>>> li[:]  3
['a', 'b', 'mpilgrim', 'z', 'example']
1 썰기 지표의 둘 중 하나가 0 이라면 그것을 생략할 수 있으며, 생략은 0을 암시한다. 그래서 이전의 예제에서의 li[:3]li[0:3]와 동일하다.
2 여기에서 대칭성에 주목하자. 이 5-요소 리스트에서, li[:3] 은 첫 번째 3개의 요소를 반환하고, li[3:]는 마지막 2 요소를 반환한다. 사실 li[:n] 는 항상 첫번째 n개의 요소를 반환하고, 그리고 li[n:]는 그 나머지를 반환할 것이다.
3 두 개의 썰기 지표가 모두 생략된다면 리스트의 모든 요소가 포함된다. 그러나 이것은 원래의li 리스트와는 동일하지 않다; 그것은 어쩌다 모두 같은 요소들을 가지게 된 새로운 리스트이다. li[:] 는 한 리스트의 완전한 복사본을 만들기 위한 간편한 방법이다.

Example 1.17. Adding elements to a list

>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li.append("new")               1
>>> li
['a', 'b', 'mpilgrim', 'z', 'example', 'new']
>>> li.insert(2, "new")            2
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']
>>> li.extend(["two", "elements"]) 3
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
1 append는 하나의 요소를 리스트의 마지막에 추가한다.
2 insert는 요소 하나를 리스트 안으로 삽입한다. 숫자 인자는 충돌을 일으켜 위치를 옮겨야 될 첫 번째 요소의 지표이다. 주목할 것은 리스트의 요소들이 반드시 서로 달라야 할 필요는 없다는 것이다; 이제는 2개의 별개의 요소로 각각 new라는 값이 li[2]li[6]에 존재한다.
3 extend는 리스트를 연결한다. extend를 다중 인자로 호출하지 않았다는 것을 주목하라; 그것을 하나의 인자, 리스트로 호출한다. 이 경우에 리스트는 두 개의 요소를 가진다.

Example 1.18. Searching a list

>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.index("example") 1
5
>>> li.index("new")     2
2
>>> li.index("c")       3
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
ValueError: list.index(x): x not in list
>>> "c" in li           4
0
1 index는 리스트안에서 어떤 값의 첫 번째 출현을 찾는다. 그리고 그 지표를 반환한다.
2 index는 리스트안에서 어떤 값의 첫 번째 출현을 찾는다. 이 경우에, new는 리스트에서 두 번 li[2]li[6]에서 나타난다. 그러나 index 는 오직 첫 번째 지표인 2 만을 반환할 것이다.
3 만약 리스트에서 값이 발견되지 않는다면, 파이썬은 예외를 발생시킨다. 이점은 다른 대부분의 언어와 현저하게 다른데, 파이썬은 어떤 유효하지 않는 지표를 반환하기 때문이다. 이것은 성가시게 보이지만, 좋은 점이다™. 왜냐하면 이후에 그 유효하지 않은 지표를 사용하려고 할 때, 문제가 있는 소스에서 프로그램이 충돌을 일으킬 것이라는 뜻이기 때문이다.
4 한 값이 리스트에 있는지 알아 보려면, in을 사용하라. 값이 발견되면 1 을 반환하고 혹은 발견되지 않으면 0을 반환한다.
Note
파이썬에는 불리언 데이타형이 없다(역주: 파이썬 2.2에서부터 불리언 형 도입). (if 서술문 같은) 불리언 문맥에서, 0 은 거짓이고 다른 모든 숫자들은 참이다. 이것은 다른 모든 데이타 형에도, 역시 확장된다. 빈 문자열 (""), 빈 리스트 ([]), 그리고 빈 사전 ({}) 은 모두 거짓이며; 다른 모든 문자열, 리스트 그리고 사전은 참이다.

Example 1.19. Removing elements from a list

>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.remove("z")   1
>>> li
['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']
>>> li.remove("new") 2
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']
>>> li.remove("c")   3
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
ValueError: list.remove(x): x not in list
>>> li.pop()         4
'elements'
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']
1 remove 는 리스트로부터 첫 번째로 출현한 값을 제거한다.
2 remove오직 첫 번째로 출현한 값만을 제거한다. 이 경우에, new는 리스트에서 두 번 나타났다. 그러나 li.remove("new") 는 첫번째 출현한 값만을 제거하였다.
3 만약 값이 리스트에서 발견되지 않는다면, 파이썬은 예외를 발생시킨다. 이것은 index 메쏘드의 행위를 그대로 반영한다
4 pop 은 재미있는 놈이다. 두 가지 일을 한다: 하나는 리스트에서 가장 마지막 요소를 제거하고 다른 하나는 삭제한 값을 반환한다. 이것은 li[-1]과는 다르다는 사실에 주목하자. 값을 반환하기는 하지만 리스트를 변경하지 않는다. li.remove(value)과도 다르다. 리스트를 변경하지만 값을 반환하지 않는다.

Example 1.20. List operators

>>> li = ['a', 'b', 'mpilgrim']
>>> li = li + ['example', 'new'] 1
>>> li
['a', 'b', 'mpilgrim', 'example', 'new']
>>> li += ['two']                2
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']
>>> li = [1, 2] * 3              3
>>> li
[1, 2, 1, 2, 1, 2]
1 리스트는 + 연산자로 또한 연결될 수 있다. list = list + otherlistlist.extend(otherlist)와 동등하다. 그러나 + 연산자는 새로이 연결된 리스트를 값으로 반환한다, 반면에 extend는 존재하는 리스트를 변경하기만 한다.
2 파이썬은 += 연산자를 제공한다. li += ['two']li = li + ['two']과 동등하다. += 연산자는 리스트, 문자열, 그리고 정수에 작동한다. 또한 사용자-정의 클래스로 덮어쓸 수도 있다. (제 3장에서 클래스에 관하여 더 자세히 다룸)
3 * 연산자는 리스트에 대해 반복자로 작동한다. li = [1, 2] * 3li = [1, 2] + [1, 2] + [1, 2]와 동등한데, 이 세개의 리스트를 하나로 연결한다.

더 읽어야 할 것

1.9 터 플 101

터플은 교환불능 리스트이다. 터플은 한 번 만들어지고 나면 어떠한 방식으로든 변경될 수 없다.

Example 1.21. Defining a tuple

>>> t = ("a", "b", "mpilgrim", "z", "example") 1
>>> t
('a', 'b', 'mpilgrim', 'z', 'example')
>>> t[0]                                       2
'a'
>>> t[-1]                                      3
'example'
>>> t[1:3]                                     4
('b', 'mpilgrim')
1 터플은 리스트와 같은 방식으로 정의된다. 다른 점은 요소들의 전체 집합을 각괄호 대신에 반괄호로 둘러싼다는 것이다.
2 터플의 요소들은 리스트와 마찬가지로 똑같이, 순서가 정의되어 있다. 터플의 지표도 리스트와 마찬가지로 똑 같이, 0 에서 시작한다. 그래서 비어있지 않은 터플의 첫 번째 요소는 항상 t[0]이다.
3 음의 지표는, 리스트와 마찬가지로 터플의 마지막에서부터 센다.
4 썰기도 역시 리스트와 똑같이 작동한다. 주목할 것은 리스트를 썰기할 때, 새로운 리스트를 획득하는 것이고; 터플을 썰기할 때는, 터플을 가진다는 것이다.

Example 1.22. Tuples have no methods

>>> t
('a', 'b', 'mpilgrim', 'z', 'example')
>>> t.append("new")    1
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'append'
>>> t.remove("z")      2
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'remove'
>>> t.index("example") 3
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'index'
>>> "z" in t           4
1
1 터플에 요소를 추가할 수 없다. 터플은 append이나 extend 메쏘드가 없다.
2 터플로부터 요소들을 제거할 수 없다. 터플에는 remove 혹은 pop 메쏘드가 전혀 없다.
3 터플에서 요소들을 탐색할 수 없다. 터플에는 index 메쏘드가 전혀 없다.
4 그렇지만, in 을 사용하면 터플에 한 요소가 있는지 없는지 조사해 볼 수 있다.

그래서 터플은 무엇에 필요한가?

Note
터플은 리스트로 변환될 수 있으며, 그 반대도 가능하다. 내장 tuple 함수는 리스트를 취하고 똑 같은 요소들을 가지는 터플을 반환하며, 그리고 list 함수는 터플을 취해 리스트를 돌려준다. 사실상, tuple은 리스트를 얼리고, 그리고 list는 터플을 녹인다.

더 읽어야 할 것

1.10. 변수를 정의하기

이제 사전, 터플, 그리고 리스트에 관하여 모든 것을 알았으므로 (오 세상에나!), 예제 프로그램 odbchelper.py으로 되돌아 가보자.

파이썬은 다른 대부분의 언어와 같이 지역 변수와 전역 변수를 가진다. 그러나 파이썬은 명시적인 변수 정의는 가지지 않는다. 변수는 한 값이 할당되면 튀어 나와 존재하다가, 영역을 벗어나게 될 때 자동으로 파괴된다.

Example 1.23. Defining the myParams variable

if __name__ == "__main__":
    myParams = {"server":"mpilgrim", \
                "database":"master", \
                "uid":"sa", \
                "pwd":"secret" \
                }

여기에는 몇가지의 재미있는 점들이 있다. 먼저, 들여쓰기에 주목하라. if 서술문은 코드 블록이며 함수와 똑 같이 들여쓰기될 필요가 있다.

둘째로, 변수는 줄연속 표식으로 작용하는 역사선(“\”)으로 여러줄에 걸쳐 나누어진 한개짜리 명령어이다.

Note
하나의 명령어가 줄연속 표식인 (“\”)로 여러줄에 걸쳐 나누어질 때, 연속된 줄은 어떤 방식으로든 들여쓰기 될 수 있다; 파이썬의 정상적인 빡빡한 들여쓰기 규칙은 적용되지 않는다. 만약 파이썬 IDE가 연속된 줄을 자동-들여쓰기 한다면, 그렇게 하지 않을 심각한 이유를 가지지 않는한 아마도 그 기본 값을 받아들이는 것이 좋을 것이다.
Note
엄밀히 이야기 해서, (사전을 정의하는 것과 같은), 반괄호, 각괄호, 혹은 활괄호 안에 있는 표현식은 줄 연속 문자(“\”)가 있든 없든 여러줄로 분리될 수 있다. 나는 필요하지 않을 때 조차도 백슬래쉬를 포함시키는데 왜냐하면 그렇게 함으로써 코드를 더 쉽게 읽을 수 있다고 생각하기 때문이지만, 그것은 스타일의 문제이다.

세번째로, myParams변수를 정의하지 않았다, 단지 하나의 값을 할당했을 따름이다. 이것은 VBScript에서 option explicit선택사항 없이 사용한 것과 비슷하다. 다행스럽게도, VBScript와는 다르게, 파이썬은 할당된 적이 없는 변수를 참조하지 못하도록 할 것이다; 그렇게 하면 예외가 일어난다.

Example 1.24. Referencing an unbound variable

>>> x
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
NameError: There is no variable named 'x'
>>> x = 1
>>> x
1

이것에 대해 언젠가는 파이썬에게 감사할 것이다

더 읽어야 할 것

1.11. 여러개의 값을 한번에 할당하기

파이썬에서 기가 막힌 프로그래밍의 지름길 중의 하나는 연속열을 사용하여 여러 값들을 한 번에 할당하는 것이다.

Example 1.25. Assigning multiple values at once

>>> v = ('a', 'b', 'e')
>>> (x, y, z) = v 1
>>> x
'a'
>>> y
'b'
>>> z
'e'
1 v 는 세 개의 요소를 가진 터플이다. (x, y, z) 는 세 개의 변수를 가진 터플이다. 하나를 다른 하나에 할당함으로써 v 의 각 값을 각각의 변수에 순서대로 할당한다.

이것은 온갖 종류의 용도를 가진다. 나는 때때로 이름들을 일정범위의 값들에다 할당하고자 한다. C 에서라면 enum을 사용하고 그리고 수작업으로 각각의 상수와 그와 연관된 값들을 나열하려고 할 것이다. 그렇게 하는 일은 그 값들이 연속적일 때는 특히나 지루해 보인다. 파이썬에서는 내장된 range 함수를 여러-값 할당에 사용하면 빠르게 연속적인 값들을 할당할 수 있다.

Example 1.26. Assigning consecutive values

>>> range(7)                                                                    1
[0, 1, 2, 3, 4, 5, 6]
>>> (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7) 2
>>> MONDAY                                                                      3
0
>>> TUESDAY
1
>>> SUNDAY
6
1 내장된 range 함수는 정수 리스트를 반환한다. 가장 단순한 형태로 range 함수는 상한값을 취해서 상한값(불포함)까지 계산된 0-기본 리스트를 반환한다. (원한다면, 다른 매개변수들을 건네주어서 기본첨자로 0말고 다른 값을 그리고 사이띄기 값으로 1말고 다른 값을 지정할 수 있다. range.__doc__ 를 출력하면 세부정보를 볼 수 있다.)
2 MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, 그리고 SUNDAY는 우리가 정의하고 있는 값들이다. (이 예제는 calendar 모듈에서 가져왔는데, 유닉스의 프로그램 cal과 비슷하게 달력을 출력하는 작고 재미 있는 모듈이다. calendar 모듈에는 요일을 위한 정수형 상수들이 정의되어 있다.)
3 이제 각 변수는 자신만의 값을 가진다: MONDAY0이고, TUESDAY1이며, 그리고 등등.

또한 다중-할당을 사용하여 단순히 모든 값들을 가진 터플을 반환함으로써 여러 값들을 반환하는 함수들을 구축할 수 있다. 달력은 그것을 하나의 터플로 취급할 수 있다. 또는 그 값들을 개별적인 변수들에 할당할 수 있다. os모듈을 포함하여 많은 표준 파이썬 라이브러리는 이런 방식을 사용한다. 이에 관해서는 제 3 장에서 논의해 보겠다.

더 읽어야 할 것

1.12. 문자열을 형식화하기

파이썬은 문자열에 삽입되는 형식화 값들을 제공한다. 아주 복잡한 표현식을 포함할 수 도 있지만, 가장 기본적인 사용법은 값들을 %s표시지정자로 문자열에 삽입하는 것이다.

Note
파이썬에서 문자열 형식화는 C 에서의 sprintf함수와 똑 같은 구문을 사용한다.

Example 1.27. Introducing string formatting

>>> k = "uid"
>>> v = "sa"
>>> "%s=%s" % (k, v) 1
'uid=sa'
1 전체 표현식은 문자열로 평가된다. 첫 번째 %sk의 값으로 대체되고; 두 번째 %sv의 값으로 대치된다. 문자열에 있는 모든 문자들은 (이 경우에는, 등호 표시) 그대로 유지된다.

(k, v)는 터플이라는 것을 주목하라. 나는 이것이 무엇엔가 쓸모가 있다고 언급한 바 있다.

단순한 문자 연결을 하기 위하여 너무 많은 일을 한다고 생각할지도 모르겠다. 문자열 형식화가 그저 단순한 연결만이 아니라는 점만 뺀다면, 여러분이 옳을지도 모른다. 그것은 결코 단순한 문자 연결이 아니며 한 편으로 강제 형변환이기도 하다.

Example 1.28. String formatting vs. concatenating

>>> uid = "sa"
>>> pwd = "secret"
>>> print pwd + " is not a good password for " + uid      1
secret is not a good password for sa
>>> print "%s is not a good password for %s" % (pwd, uid) 2
secret is not a good password for sa
>>> userCount = 6
>>> print "Users connected: %d" % (userCount, )           3 4
Users connected: 6
>>> print "Users connected: " + userCount                 5
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
TypeError: cannot add type "int" to string
1 + 는 문자열 연결 연산자이다.
2 이러한 사소한 경우에는, 문자열 형식화는 결합과 동일한 결과를 달성한다.
3 (userCount, )는 하나의 요소를 가진 터플이다. 사실, 구문이 좀 이상하게 보이지만, 그럴만한 이유가 있다: 그것은 확실히 터플이다. 실제로 리스트, 터플, 혹은 사전을 정의할 때 항상 쉼표를 포함할 수 있다. 그러나 여기에서 쉼표는 하나의 요소를 가진 터플을 정의할 때 요구된다. 만일 쉼표가 요구되지 않는다면, 파이썬은 (userCount)가 하나의 요소를 가진 터플인지 혹은 단순히 userCount의 값인지 알 수가 없을 것이다.
4 문자열 형식화는 %s 대신에 %d 를 지정함으로써 정수와 작동한다.
5 문자열을 비-문자열과 결합하려는 시도는 예외를 발생시킨다. 문자열 형식화와는 다르게, 문자열 연결은 모든 것이 이미 문자열일 때만 작동한다.

더 읽어야 할 것

1.13. 리스트를 짝짓기

파이썬의 가장 강력한 특징중의 하나는 리스트 통합능력인데, 이것은 함수를 리스트의 각 요소에 적용함으로써 리스트를 다른 리스트와 짝짓는 간결한 방법을 제공해 준다.

Example 1.29. Introducing list comprehensions

>>> li = [1, 9, 8, 4]
>>> [elem*2 for elem in li]      1
[2, 18, 16, 8]
>>> li                           2
[1, 9, 8, 4]
>>> li = [elem*2 for elem in li] 3
>>> li
[2, 18, 16, 8]
1 이것을 이해하기 위해서는, 오른쪽에서 왼쪽으로 보라. li는 짝짓고 있는 리스트이다. 파이썬은 한번에 한 요소씩 li 리스트를 회돌이 하면서, 임시적으로 각 요소의 값을 elem 변수에 할당한다. 파이썬은 elem*2 함수에 적용하고 그리고 그 결과를 반환되는 리스트에 추가한다.
2 리스트 통합은 원래의 리스트를 변경하지 않는다는 것을 주목하라.
3 리스트 통합의 결과는 짝짓고 있는 변수에 할당하는 것이 안전하다. 거기에는 경쟁 조건도 없으며 혹은 걱정할 만한 어떤 기이함도 없다; 파이썬은 새로운 리스트를 메모리에 구축한다. 리스트 통합이 완결되면, 그 결과를 변수에 할당한다.

Example 1.30. List comprehensions in buildConnectionString

["%s=%s" % (k, v) for k, v in params.items()]

먼저, params 사전의 items함수를 호출하고 있는 것에 주목하자. 이 함수는 사전의 데이타를 모두 가진 터플의 리스트를 반환한다.

Example 1.31. keys, values, and items

>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> params.keys()   1
['server', 'uid', 'database', 'pwd']
>>> params.values() 2
['mpilgrim', 'master', 'sa', 'secret']
>>> params.items()  3
[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]
1 사전의 keys 메쏘드는 모든 키들을 가진 리스트를 반환한다. 리스트는 사전이 정의되었을 때의 순서가 아니다 (기억하라, 사전의 요소들은 순서가 없다). 그러나 그것은 리스트이다.
2 values 메쏘드는 모든 값들을 가진 리스트를 반환한다. 그 리스트는 keys 에 의해서 반환된 리스트와 같은 순서이다. 그래서 n의 모든 값들에 대하여 params.values()[n] == params[params.keys()[n]]이다 .
3 items 메쏘드는 (key, value)의 형태인 터플의 리스트를 반환한다. 리스트는 사전에 있는 모든 데이타를 포함한다.

이제 buildConnectionString이 무엇을 하는지 살펴 보자. 이것은 리스트를 params.items()로서 취하고, 그 리스트를 새로운 리스트에 짝짓기 해서 문자열 형식화를 각 요소에 적용한다. 새로운 리스트는 params.items()와 똑 같은 개수의 요소를 가지지만, 새로운 리스트의 각 요소는 params 사전에서 유래한 키와 그와 연관된 값을 모두 포함하는 문자열이 될 것이다.

Example 1.32. List comprehensions in buildConnectionString, step by step

>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> params.items()
[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]
>>> [k for k, v in params.items()]                1
['server', 'uid', 'database', 'pwd']
>>> [v for k, v in params.items()]                2
['mpilgrim', 'sa', 'master', 'secret']
>>> ["%s=%s" % (k, v) for k, v in params.items()] 3
['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
1 변수 두 개를 사용하여 params.items() 리스트를 반복한다는 것을 주목하라. 이것은 여러-변수 할당의 또 다른 사용법이다. params.items()의 첫번째 요소는 ('server', 'mpilgrim')이다, 그래서 리스트 통합의 첫 반복에서, k'server'를 확보할 것이고 v'mpilgrim'을 획득할 것이다. 이 경우에 v의 값을 무시하고 있으며 반환되는 리스트에 k 값만을 포함하고 있다. 그래서 이 리스트 통합은 params.keys()와 동등한 결과로 끝난다. (실제 코드라면 이와 같은 리스트 통합을 사용하지 않으려고 할지도 모르겠다; 그러나 이것은 대단히 간단한 예제이다. 여기에서 무슨일이 일어나는지 훓어 볼 수 있다.)
2 여기에서도 같은 일을 하지만, k의 값은 무시한다. 그래서 이 리스트 통합은 params.values()와 동등한 결과로 끝난다..
3 위의 두 예제를 간단한 문자열 형식화로 결합하면, 사전의 각 요소의 키와 값 모두를 포함하는 문자열의 리스트를 얻는다. 이것은 의아하게도 프로그램의 출력결과와 비슷하게 보인다; 아직 남아 있는 일이라면 이 리스트의 구성요소들을 하나의 문자열로 결합하는 것이다.

더 읽어야 할 것

1.14. 리스트를 연결하고 문자열을 분리하기

키-값 쌍의 리스트는 key=value의 형태이다. 그것들을 하나의 문자열로 결합하고자 한다. 문자열의 어떤 리스트라도 한 개의 문자열로 결합하려면, 문자열 객체의 join 메쏘드를 사용하라.

Example 1.33. Joining a list in buildConnectionString

    return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

계속 하기 전에 주목할 만한 흥미로운 사실은 반복해서 말하지만 함수는 객체이며 문자열도 객체이고 모든 것이 객체라는 것이다. 문자열 변수(variables)도 객체라고 주장할지 모르겠다. 그러나 아니다. 다음 예제를 잘 살펴보면, ";" 문자열 그 자체가 객체라는 것을 알 것이다. 그리고 그 객체의 join 메쏘드를 호출하고 있다는 것을 알 것이다.

어쨋든, join 메쏘드는 리스트의 요소들을 하나의 문자열로 결합하는데, 각각의 요소들은 쌍-반점으로 분리된다. 구분자가 반드시 쌍-반점일 필요는 없다; 한개의 문자일 필요는 더더욱 없다. 어떠한 문자열도 될 수 있다.

Important
join 은 문자열의 리스트에만 작동한다; 어떠한 강제 형변환도 하지 않는다. 문자열이 아닌 요소들을 하나 이상 가지고 있는 리스트를 결합하면(join) 예외가 일어난다.

Example 1.34. Output of odbchelper.py

>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> ["%s=%s" % (k, v) for k, v in params.items()]
['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
>>> ";".join(["%s=%s" % (k, v) for k, v in params.items()])
server=mpilgrim;uid=sa;database=master;pwd=secret

그러면 이 문자열은 help 함수로부터 반환되어 호출블록에 의해 출력된다. 이 장을 읽기 시작할 때에 감탄했었던 그 출력을 보여 준다.

역사에 대한 환기 : 처음 파이썬을 배울 시절 나는 join이 리스트의 메쏘드가 되어야 한다고 예상했었다. 그러면 구분자를 인자로 취할 것이다. 많은 사람들이 같은 방식으로 생각한다. join 메쏘드 뒤에는 숨겨진 이야기가 있다. 파이썬 1.6 이전 버전에서 문자열은 이러한 모든 유용한 메쏘드들을 가지고 있지 않았다. 따로 string 모듈이 있었는데 모든 문자열 함수를 담고 있었다; 각 함수는 문자열을 자신의 첫번째 인자로 취했다. 함수는 문자열 보다 더 중요하게 여겨졌다. 그것은 lower, upper, 그리고 split과 같은 함수들에는 의미가 있었다. 그러나 많은 핵심 파이썬 프로그래머들은 그 새로운 join 메쏘드에 반대하면서, 그것은 대신에 리스트의 메쏘드가 되어야만 한다든가, 혹은 그것은 절대로 움직여선 안되고 단지 구형 string 모듈(여전히 많은 유용한 것들을 가지고 있다)의 일부에 머물러야 한다고 주장하였다. 나는 그 새로운 join 메쏘드를 단독으로 사용한다. 그러나 여러분은 같은 방식으로 작성되어진 코드를 볼 수 있을 것이다. 그리고 그 때문에 괴롭다면, 대신에 구형 string.join 함수를 사용하면 된다.

아마도 문자열을 리스트로 쪼개는 비슷한 메쏘드가 있는지 궁금할 것이다. 물론 있다. 그것은 split이라고 부른다.

Example 1.35. Splitting a string

>>> li = ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
>>> s = ";".join(li)
>>> s
'server=mpilgrim;uid=sa;database=master;pwd=secret'
>>> s.split(";")    1
['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
>>> s.split(";", 1) 2
['server=mpilgrim', 'uid=sa;database=master;pwd=secret']
1 split는 문자열을 여러-요소 리스트로 쪼개므로써 join의 반대가 된다. 구분자 (“;”)가 완전히 생략되었음을 주목하라; 그것은 반환된 리스트의 요소중 어느 것에도 나타나지 않는다.
2 split는 쪼개질 횟수로 선택적인 두 번째 인자를 취한다. (“"음, 선택적 인자라...” 함수에서 이렇게 하는 법을 다음장에서 배워 보겠다.)
Note
anystring.split(delimiter, 1) 는 유용한 테크닉이다. 문자열을 검색해서 하부문자열을 찾고 그리고 그 하부문자열 앞의 모든 것들과 (반환된 리스트의 첫 번째 요소가 됨) 그 하부문자열 뒤의 모든 것들과 (두 번째 요소가 됨) 작업하고자 할 때 유용하다.

더 읽어야 할 것

1.15. 요 약

odbchelper.py 프로그램과 그 출력은 이제 완전히 이해가 되었으리라 믿는다.

Example 1.36. odbchelper.py

def buildConnectionString(params):
    """Build a connection string from a dictionary of parameters.

    Returns string."""
    return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

if __name__ == "__main__":
    myParams = {"server":"mpilgrim", \
                "database":"master", \
                "uid":"sa", \
                "pwd":"secret" \
                }
    print buildConnectionString(myParams)

Example 1.37. Output of odbchelper.py

server=mpilgrim;uid=sa;database=master;pwd=secret

다음장으로 다이빙해 들어가기 전에, 편안하게 이러한 모든 것들을 하고 있는지 확인하라:



[1] 다른 프로그래미밍 언어들은 “객체(object)”를 다른 방식으로 정의한다. 어떤 언어에서는, 모든 객체는 반드시 속성과 메쏘드를 가져야 한다는 것을 의미한다; 다른 언어에서는, 모든 객체는 하부클래스화가 가능해야 한다는 것을 의미한다. 파이썬에서 그 정의는 훨씬 느슨하다; 어떤 객체는 속성도 메쏘드도 가지지 않는다 (이것에 관해서는 나중에 더 자세히 다룸), 그리고 모든 객체가 하부클래스화가 가능한 것도 아니다. (이것에 관해서는 제 3장에서 더 자세히 다룸). 그러나 모든 것은 객체이다. 변수에 할당되어 질 수 있고 인자로서 함수에 건네질수 있다는 점에서 (이것에 관해서는 제 2장에서 더 자세히 다룸) 모든 것은 객체이다.

[2] 실제로는 더 복잡하다. 사전의 키는 반드시 교환불가능해야 한다. 터플 자체는 교환불가능하지만, 리스트로 이루어진 터플을 가진다면, 그것은 교환가능으로 간주되고 그것을 사전의 키로 사용하는 것은 안전하지 않다. 오직 문자열, 숫자로 이루어진 터플들만이 혹은 다른 사전-적합 터플만이 사전의 키로 사용하는 것이 좋다.


 서 문 목 차 제 2 장 검사의 힘 >>