파이썬은 동적 객체 지향 언어입니다. 동적이라는 말의 의미는 이미 파이썬 일기의 초장에 정리해놨으니, 이번엔 객체 지향이라는 말의 의미를 알아봅시다. 객체, 지향, 이 두 단어는 따로 떼어 놓으면 전혀 어려운 뜻이 아닌데 붙여 놓으니까 무슨 말인지 하나도 이해가 안 갑니다.

이럴 때는 위키 피디아님에게 도움을 청하는 것도 하나의 방법입니다.

Object-oriented programming (OOP) is a programming paradigm that uses "objects" — data structures consisting of datafields and methods — and their interactions to design applications and computer programs. Programming techniques may include features such as information hiding, data abstraction, encapsulation, modularity, polymorphism, and inheritance. It was not commonly used in mainstream software application development until the early 1990s. Many modern programming languages now support OOP.

라는군요.

요약하자면, 객체 지향 프로그래밍은 프로그래밍을 할 때 "객체"를 중심으로 사고, 생각을 한다는 것입니다. 객체 지향 프로그래밍 이전의 프로그래머들은 명령을 중심으로 생각했었죠. 그나저나 여기에서 말하는 객체는 또 무슨 의미일까요? 그냥 단순하게 우리가 앞에서 살펴봤던 변수와 메쏘드를 함께 갖고 있는 "무엇"이라고 생각하면 됩니다. 앞에서 인용한 설명대로, 객체 내의 변수와 메쏘드는 긴밀하게 상호 동작합니다(그렇지 않으면 한 객체 안에 엮어놓을 이유가 없겠죠!).

인용구의 나머지 부분은 나중에 다시 한번 이야기하기로 하고, 이제는 클래스에 대해 이야기를 시작하겠습니다.

클래스와 객체의 관계는 자료형과 변수의 관계라고 생각하면 딱 맞습니다. 파이썬에서는 모든 것이 객체이므로 자료형이 클래스이고 클래스가 자료형이며, 변수가 객체고 객체가 변수라고 할 수 있습니다. 우리가 지금까지 만들어 왔던 객체들은 모두 파이썬에 내장되어 있는 클래스들을 이용한 것입니다. int, float, string, tuple, list 는 파이썬의 내장 클래스의 일부입니다. 이들은 다시 새로운 클래스를 만들 때 재료로 사용되곤 합니다.

파이썬의 클래스는 다음과 같이 class 키워드를 이용하여 선언합니다. 그리고 그 안에 클래스의 멤버들(변수, 메쏘드)를 선언하면 기본적인 클래스가 완성됩니다.

>>> class A :
    a = 0
    b = 0
    def printMembers(self) :
        print( self.a, self.b )

         >>> obj = A() >>> obj.a = 3 >>> obj.b = 4 >>> obj.printMembers() 3 4

위 코드에서 중요한 건 class 키워드입니다. 우리는 위에서 A라는 클래스를 선언했고, A 클래스 변수 두 개(a와 b), 함수 하나(printMembers)를 정의했습니다. a와 b에 대해서는 특별히 볼 것이 없습니다. 클래스 안에서 선언되었다는 것 말고는 특별한 것이 없습니다. 하지만 printMembers()는 보통의 함수와 다른 것을 갖고 있습니다. 보이나요?

예, self 입니다. self 는 객체 자신을 가리키는 변수로써, self라는 이름은 파이썬에 키워드로 예약되어 있습니다. (즉, 우리는 self라는 변수를 임의로 만들어 쓸 수 없다는 뜻입니다. ) 파이썬은 클래스의 메쏘드로 하여금 반드시 self 매개 변수를 받는 꼴로 구현하도록 강요합니다. 대신 이 메쏘드를 실제로 호출할 때는 self 에 아무것도 대입하지 않아도 됩니다. 마치 self 매개 변수는 없는 것처럼 사용하면 됩니다.

self가 객체 자신을 가리킨다고 했는데, 그럼 self를 통하면 객체의 멤버와 메쏘드 모두에게 접근이 가능하겠죠? self 뒤에 마침표(.)를 찍고 변수 또는 메소드의 이름을 적어주면 됩니다. 다음과 같이 말입니다.

>>> obj = A()
>>> obj.a = 3
>>> obj.b = 4
>>> obj.printMembers()

아, 중요한 것을 빼먹었네요. 위 코드에서 obj를 생성하기 위해 A()라는 함수를 호출해서 그 결과를 대입하는 부분이 있죠? 여기에서 A()를 생성자(Constructor)라고 합니다. 생성자는 클래스와 같은 이름을 가지며, 클래스를 만들어주는 역할을 하는 함수입니다. 생각해보니, 우리는 A() 생성자를 구현한 적이 없습니다. 하지만 우리는 호출을 했고, A() 생성자는 우리가 원하는 대로 객체를 만들어 반환했습니다. 이것은 기본 생성자(Default Constructor) 때문입니다. 우리가 생성자를 따로 만들지 않아도 파이썬에서 기본 생성자를 제공합니다.

클래스를 사용하다 보면 어떤 때는 객체를 생성할 때 일부 멤버 변수를 원하는 값으로 초기화하고 싶을 때가 있습니다. 이런 경우에는 생성자를 직접 구현하는 것이 좋은 답이 됩니다. 생성자를 호출할 때는 클래스의 이름 뒤에 ()만 붙이면 되지만, 구현할 때의 생성자는 __init__()라는 이름을 가집니다. __init__()을 구현하면, 우리는 클래스() 로 호출해서 사용하는 것이죠.

한편, __init__() 도 클래스의 메쏘드이기 때문에 self 매개 변수는 반드시 있어야 합니다. 추가적인 매개 변수는 self 뒤에 콤마(,)로 구분해서 열거하면 됩니다. 다음 코드의 NameCard 클래스를 보면 이해가 금방 갈 겁니다.

>>> class NameCard : 
           name = "" 
           cp_number = "" 
           def __init__(self, name, cp_number) : 
               self.name = name 
               self.cp_number = cp_number 
>>> sean = NameCard( "Sean", "010-5555-7777" ) 
>>> sean.name 
'Sean' 
>>> sean.cp_number 
'010-5555-7777' 

자, 이렇게 해서 간단한 클래스를 만드는 데까지 공부를 했습니다. 본격적인 객체 지향 프로그래밍을 위해서는 상속이나 오버로딩, 오버라이딩에 대해 공부를 해야 하는데, 벌써 여기까지 오는 데도 상당한 시간이 걸렸습니다. 앞으로 지금처럼 일기 형식으로 글을 남길지는 고민입니다. 파이썬 일기는 온라인 문서만으로 공부했을 때 어느 정도 시간이 걸리는지, 얼마나 스트레스를 덜 받으면서 새 언어를 익힐 수 있는지를 보고자 하는 개인적인 실험이었습니다.

실험의 중간 결과를 말씀드리자면, 온라인 문서만으로는 제대로 공부하는 것은 어렵다는 판단이 섰습니다. 이런 식으로는 제 스스로 공부하는 데에도 어려움이 있고 의미 있는 문서를 남기고자 하는 취지도 살리질 못할 것 같습니다(그래서 #6 파이썬 일기부터는 일기 형식이 아닌 강좌 형식을 취했습니다.).

뭔가 더 좋은 방법을 찾아봐야겠습니다. 방법이... 있겠죠? ^^;

저작자 표시 변경 금지
Posted by seanlab

Trackback Address :: http://www.seanlab.net/trackback/25 관련글 쓰기

댓글을 달아 주세요

다음과 같은 코드가 있다고 해봅시다

>>> a = 2
>>> b = 3
>>> c = 4
>>> for i in range( 0, c + 1) :
	if i == 0 :
		x = 1
	elif i == 1 :
		x = a
	else :
		x = x * a
>>> print ( a, "의", c, "제곱은 : " , x )
2 의 4 제곱은 :  16
>>> for i in range( 0, c + 1) :
	if i == 0 :
		x = 1
	elif i == 1 :
		x = b
	else :
		x = x * b
>>> print ( b, "의", c, "제곱은 : " , x )
3 의 4 제곱은 :  81 

이게 무슨 일을 하는 코드 같습니까? (힌트: 출력 결과를 보세요.) 이 코드는 a의 c제곱, b의 c제곱을 계산해서 출력하는 일을 합니다. 처음 세 줄은 a, b, c를 할당하고 4번째 줄부터 이어지는 for 블록은 a의 c제곱을 처리합니다.for 블록 안에서 i가 0일 때는 x에 1을 저장하고, i가 1일 때는 a를 저장합니다. 그리고 그 이상부터는 루프가 종료할 때까지 x 에 x와 a를 곱한 값을 저장해 나갑니다. 그 아래에 있는 b를 제곱하는 코드도 변수 a가 b로 바뀌었을 뿐, 완전히 똑 같은 코드입니다.

위 코드에는 두 가지 문제가 있습니다. 하나는 이게 무슨 일을 하는 코드인지 당최 알아보기가 힘들다는 것이고, 또 하나는 같은 코드가 중복되어 사용되고 있다는 것입니다. 오늘 이야기할 함수는 이 두 가지 문제를 한 번에 해결할 수 있는 친구입니다.

파이썬에서는 함수를 다음과 같이 키워드 def를 이용하여 정의합니다.

def 함수명 ( 매개 변수 목록 ) :
	명령1
	명령 2
	…
	return 결과

함수 정의의 맨 첫 줄에 있는 매개 변수 목록은 함수가 계산에 사용할 변수를 입력하는 곳입니다. 외부에서 함수 안에 어떤 데이터를 밀어 넣고 싶으면 이곳에 미리 매개 변수를 정의해둬야 합니다. 한편 매개 변수 목록과는 달리 가장 마지막에 오는 return 은 함수의 결과를 반환하는 구문입니다. 예를 들어 return 11 이라고 하면 11을 함수의 결과로 반환하게 됩니다. 아, 위 형식에서 제가 return을 가장 아래쪽에 두긴 했지만 return은 어느 곳에나 둘 수 있고, 여러 곳에 둘 수도 있습니다. 길게 설명하는 것보다 예제를 하나 보는 게 낫겠죠? 다음은 두 변수를 입력 받아 크기를 비교하여 큰 변수를 다시 반환하는 max() 함수입니다.

>>> def max ( a, b ) :
	if a > b :
		return a
	else :
		return b
	
>>> max( 3, 4 )
4
>>> max ( 33, 2)
33

함수는 딱 두 가지만 기억하면 됩니다. 입력: 매개 변수, 출력 : return.

그럼 이제 처음에 봤던 문제의 코드를 다시 함수를 이용하여 간추려 보겠습니다.


>>> def myPow( base, exponent ) :
	result = 0
	for i in range( 0, exponent + 1) :
		if i == 0 :
			result = 1
		elif i == 1 :
			result = base
		else :
			result = result * base
	return result

>>> print ("2의 4제곱은 : " , myPow(2, 4 ))
>>> print ("3의 4제곱은 : " , myPow(3, 4 ))

오늘은 함수에 대해 간단히 정리했습니다. 내일은 클래스가 무엇인지, 클래스를 어떻게 정의하는지 정리해보겠습니다.

Posted by seanlab

Trackback Address :: http://www.seanlab.net/trackback/24 관련글 쓰기

댓글을 달아 주세요

continue와 break는 루프의 실행을 건너뛰거나 멈추게 하는 구문이다. 이름을 보면 그 의미를 짐작할 수 있는데, continue는 루프를 한 회 건너 뛰게 하고 break는 루프를 중단하게 만든다. 사용방법은 각각 다음과 같다.

먼저 continue 문 예제.

>>> for i in range(0, 5) :
        if i == 2 :
            continue
        print( i )
        
0
1
3
4
 

다음은 break문 예제.

>>> for i in range(0, 5) :
        if i == 2 :
            break;
        print( i )
0
1 

continue와 break는 for 문에서만 사용할 수 있는 것이 아니다. while 루프에서도 사용할 수 있다.

>>> i = 0
>>> while (1) :
        i += 1
        if ( i == 3 ) :
            continue
        if ( i == 5 ) :
            break
        print( i )
1
2
4 

이렇게 해서 파이썬의 기본 초식은 익힌 것 같다. 다음에는 코드를 간추려 함수로 만드는 방법을 정리해야겠다.

여러 가지 일을 병행해서이기도 하지만, 현재 진행 방식이 너무 느린 것 같아 고민이다. 함수까지 익히고 나면 뭔가를 만들면서 부딪히는 방식으로 속도를 높여볼 계획이다. 점심시간이 벌써 끝났네. T-T 이제 일해야겠다.

저작자 표시 비영리 변경 금지
Posted by seanlab

Trackback Address :: http://www.seanlab.net/trackback/21 관련글 쓰기

댓글을 달아 주세요

파이썬에서 지원하는 루프문은 for와 while 두 가지다. 우선 for 문에 대해 공부해보자.

#5.2. for문

for 문은 코드를 작성할 때 프로그래머가 루프의 반복 횟수를 미리 정해놓았을 때 주로 사용하며, 다음의 꼴로 쓰면 된다.

for 변수 in 순서열 :
    명령1
    명령2
    … 

여기에서 순서열은 리스트, 튜플, 문자열, 바이트 배열 등 어떤 것을 사용해도 괜찮다. for 문은 순서열의 각 원소를 처음부터 차례로 순회하면서 변수에 담아낸다. for문에 가장 많이 사용되는 순서열은 레인지(Range)인데, range() 함수에 최소, 최대값을 매개 변수로 넘기면 바로 최소값부터 최대값 사이의 정수를 원소로 갖는 레인지 순서열을 만들 수 있기 때문이다. 만약 순서열이 range(0, 5) 함수를 이용하여 생성된다면 변수에는 0, 1, 2, 3, 4 가 차례대로 담겨질 것이다. 다음 예제 코드를 보면 이게 무슨 말인지 금방 이해할 수 있을 것이다.

>>> for x in range(0, 5) :
    print( x )
    
0
1
2
3
4 

for를 한번 중첩해서 추억의 별찍기를 해보자.

>>> for i in range(0, 6) :
        for j in range(0, i) :
            print( "*", end = "", )
        print()
*
**
***
****
***** 

#5.3. while 문

while 문도 for문이랑 사용법이 비슷하다.

문은 코드를 작성할 때 프로그래머가 루프의 반복 횟수를 미리 정해놓았을 때 주로 사용하며, 다음의 꼴로 쓰면 된다.

while 수행 조건 :
    명령1
    명령2
    … 

백번 읽어보는 것보다 하나의 예제 프로그램을 만들어 보는 것이 훨씬 기억도 잘되고 이해도 잘된다. 예제 코드를 작성해 보자.

>>> i = 100
>>> while i > 0 :
        print( i, end=' ' )
        i = i -1
    
100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 
저작자 표시 비영리 변경 금지
Posted by seanlab

Trackback Address :: http://www.seanlab.net/trackback/20 관련글 쓰기

댓글을 달아 주세요

프로그램은 컴퓨터가 할 일의 목록이다. 프로그래머가 컴퓨터에게 할 일의 목록을 내주면, 컴퓨터는 프로그램에 기록되어 있는 일 목록을 보고 그 대로 수행한다. 프로그래밍에서 "흐름(Flow)"라고 하면 컴퓨터에 내려지는 명령의 순서를 가리키는 말이다. 다음과 같이 프로그램을 작성하면 컴퓨터는 1, 2, 3번의 작업을 순서대로 처리할 것이다.

  1. a 에 사용자로부터 입력 받은 수를 저장하라.
  2. b에 3/a의 결과를 저장하라.
  3. a와 b를 출력하라.

이 프로그램은 간단하긴 하지만 문제가 한가지 있다. 만일 a가 가지면 안 되는 수, 예를 들어 0을 사용자로부터 입력 받게 되면 이 프로그램은 오류를 일으키게 된다. 이것을 방지할 수 있는 방법이 있어야 하지 않겠는가? 다음과 같이 말이다.

  1. a에 사용자로부터 입력 받은 수를 저장하라.
  2. a가 0 이라면 프로그램을 종료하고, 그렇지 않으면 다음 명령을 수행하라.
  3. b 에 3/a의 결과를 저장하라.
  4. a와 b를 출력하라.

2번의 "a가 0이라면 ~하고, 그렇지 않다면 ~하라"를 주목하자. 프로그램이 직선으로 흐르다가 이 문장을 통해 방향을 이리 저리 틀게 되었다. 오늘은 이와 같이 프로그램 흐름의 방향을 틀거나 반복할 수 있도록 하는 파이썬의 "흐름 제어(Control Flow)"를 살펴볼 계획이다.

흐름 제어에는 크게 두 가지가 있다. 하나는 프로그램의 흐름을 좌/우로 가르는 분기(branch)문, 또 다른 하나는 프로그램의 일부를 반복 동작하게 하는 반복(loop)문이다. 파이썬이 제공하는 분기문에는 if 문이 있고 반복문에는 for와 while문이 있다. 다음에서 먼저 if 문을 알아보자.

#5.1. if 문

초등학교를 졸업했다면 if가 무슨 뜻인지 알고 있을 것이다 if는 '~라면'이라는 뜻이다. 신라면, 너구리 이런 라면이 아니고 어떤 상황을 가정할 때 사용하는 라면 말이다. 예를 들어 '내가 산 로또가 1등이라면' 같은 것 말이다. 파이썬 코드에서도 if 문을 이용해서 어떤 상황을 가정하고 그 상황에 필요한 명령을 사용할 수 있다.

if 조건 문장 :
    명령1
    명령2
    ….
else :
    명령2
    명령3
    …

if문의 조건은 콜론( : )으로 끝나며, 그 밑 줄부터는 조건이 참(True)인 경우 실행할 명령들이 위치한다. 만약 if에서 명시한 조건이 거짓(False)인 경우에는 else : 이후의 명령들이 실행된다. 여기에서 잘 봐야 할 것이 있다. 바로 if 문에 명시한 조건 하에서 실행되어야 하는 명령들(그리고 그 조건이 맞지 않아 else : 밑에서 실행되어야 하는 명령들)은 모두 들여쓰기로 쓰여있어야 한다는 것이다. 예를 한번 보자.

>>> a = int( input( "수를 입력하세요 : " ) )
수를 입력하세요 : 78
>>> if a != 0 :
    print( "a는 크다!" )
    print( "a는 크다!" )
    print( "a는 크다!" )
else :
    print( "a는 0이다.")
    print( "a는 0이다.")
    
a는 크다!
a는 크다!
a는 크다!

위 코드에서 print("a는 크다!")가 쓰여 있는 세 줄이 바로 a가 0이 아닌 경우 실행되어야 하는 부분이다. 이 세 줄처럼 하나의 묶음으로 처리되는 코드를 가리켜 "블록(Block)"이라 한다. 파이썬은 코드가 연속한 줄에 위치한다고 해서 같은 블록으로 인지하지는 않는다. 같은 깊이로 들여쓰기가 되어 있어야 블록으로 인지한다. 그래서 위 예제에서 if 블록이라 하면 세 줄의 print( "a는 크다!" )를 가리키는 것이고, else 블록이라 하면 print("a는 0이다.")의 두 줄을 가리키는 말이 되는 것이다.

조금 전에 살펴 봤던 예제처럼 조건이 하나만 있을 수도 있지만, 조건이 여러 개 필요한 경우도 다반사다. 이런 경우를 위해 if와 함께 쓸 수 있는 elif 문이 있다. elif는 else if 의 줄임말로, if문과 똑같이 조건을 명시하면 된다. 사용 예는 다음과 같다.

>>> a = int ( input( "숫자를 입력하세요 : ") )
숫자를 입력하세요 : 1
>>> if a == 0 :
    print("a는 0")
elif a == 1 :
    print("a는 1")
elif a == 2 :
    print("a는 2")
else :
    print("a는 0도, 1도, 2도 아님.")

a는 1

파이썬의 분기문은 if 하나 뿐이다. C나 Java, C#에서 제공하는 것처럼 switch 문 등은 제공하지 않는다. 아쉽긴 하지만 이건 어디까지나 파이썬을 만든 귀도형님의 취향이니 존중을 해드려야겠다. 내일은 반복문에 해당하는 for문과 while 문을 공부해야겠다.

저작자 표시 비영리 변경 금지
Posted by seanlab
TAG If, 파이썬

Trackback Address :: http://www.seanlab.net/trackback/18 관련글 쓰기

댓글을 달아 주세요

 내 것으로 만든 다음에 글을 쓰는 것과 공부해가면서 글을 쓰는 것은 천지차이라는 것을 절실히 느끼고 있다. 좋은 책들이 이미 여러 권 나와 있기 때문에 그 책을 보고 공부하면 몇일 안에 뗄 수도 있을 것 같지만, 나는 그냥 파이썬을 공부하는 것이 아니라 일종의 실험을 하고 있는 것이다. 공부 과정을 기록으로 남겼을 때 공부 자체에 어떤 도움이 되는지도 궁금하고 다른 사람한테 어떤 도움을 줄 수 있을지도 궁금하다. 파이썬 언어를 빨리 익혀서 급하게 사용해야 하는 것도 아니고, 그냥 하루 하루 조금씩 알아가는 재미를 느끼고 싶은 것도 이렇게 기록을 남기는 이유중에 하나다.

 그나저나 애초에 계획했던 진도 중에 기초 자료형까지 공부를 이제 마쳤다. 마쳤다라는 표현이 안 어울리긴 하지만, 아무튼 나는 진도를 뺐다. 이제 흐름 제어문을 익히고, 어떻게 코드를 추상화 하는지도 익혀야 한다. 그리고 파이썬으로 객체 지향적으로 프로그래밍을 하는 것이 익숙해지면 좀더 다이내믹하게 코드를 다루는 방법을 연습하려 한다.

 C# 4.0 원고도 준비해야 하는데 고민이 크다. 아마 전에 써둔 C# 2.0 원고는 안 쓰게 될 것 같다. 대학교 다닐 때 쓴 C# 1.0 원고를 개정해서 C# 2.0 원고를 썼는데, 부족해보이는 것이 너무 많기 때문이다. 처음부터 쓰려니 부담이 상당한 것이 사실이지만, 그래도 쓰는 재미가 쏠쏠하니 해볼만 하다고 생각이 든다. 갑자기 왜 C# 4.0으로 이야기가 샜지? ^^;

저작자 표시 비영리 변경 금지
Posted by seanlab

Trackback Address :: http://www.seanlab.net/trackback/15 관련글 쓰기

댓글을 달아 주세요

불변/가변 바이트 배열은 바이트와 또 하나의 문자열 자료형이라고 생각하면 이해가 쉽다. 문자열 객체가 갖고 있는 대부분의 메소드를 바이트 배열도 거의 다 갖고 있다. 단, 문자열에서는 문자 코드를 유니코드로 사용하는데 반해, 바이트 배열에서는 문자의 범위가 정수 0~256 코드로 한정된다는 점이 다르다. 원래의 이름은 bytes, byte array지만 내 나름대로 의역해서 불변 바이트 배열, 가변 바이트 배열이라 이름 붙였다(이의 제기 환영합니다. 굽신굽신). 불변/가변 바이트 배열은 불변/가변이라는 속성 말고는 큰 차이가 없기 때문에 어느 한쪽을 알아두면 나머지는 자동으로 알게 되는 것이나 다름 없다. 그래서 오늘은 불변 바이트 배열에 대해 정리를 해보고, 그 다음에 가변 바이트 배열을 다루면서 불변 바이트 배열과 다른 점을 다룰 계획이다.

불변 바이트 배열은 문자열 상수 앞에 b를 붙이거나 문자열의 bytes() 내장함수 또는 문자열의 encode() 메소드를 이용해서 만들 수 있다. 먼저 b를 이용하는 선언은 다음과 같다.

>>> b = b'abc'
>>> b
b'abc'
>>> b[0]
97
>>> b[1]
98
>>> b[2]
99

bytes() 내장 함수는 튜플, 리스트, 문자열 등으로부터 바이트 배열을 만들어 준다.

>>> b = bytes( (97, 98, 99) ) #튜플로부터 바이트 배열 생성
>>> b
b'abc'
>>> b = bytes( 'abc', 'ascii' ) # 문자열로부터 바이트 배열을 생성할 때에는 인코딩을 매개 변수를 같이 넣어줘야 한다.
>>> b
b'123'

문자열에서 바이트 배열을 만들어냈다. 그렇다면 문자열을 바이트 배열로부터 만들어 낼 수 있을까? 있다. decode() 메소드를 이용하면 된다.

>>> b = bytes( 'abc', 'ascii' )
>>> b.decode()
'abc'

앞서 bytes() 내장 함수를 이용해서 문자열 객체를 바이트 배열로 바꿨는데, 문자열의 encode() 메소드를 사용해도 같은 결과를 얻을 수 있다.

>>> s = 'abc'
>>> b = s.encode()
>>> b
b'abc'

불변 바이트 배열은 그야말로 '불변'이다. 일부를 바꾸려고 시도하면 파이썬 인터프리터가 그런 짓 하지 말라고 나를 나무랄 것이다. 한번 해보자.

>>> b = b'123'
>>> b[0] = 100
Traceback (most recent call last):
File "<pyshell#11>", line 1, in <module>
b[0] = 100
TypeError: 'bytes' object does not support item assignment

혹시나 했는데 역시나였다. 이제 가변 바이트 배열을 살펴보자. 가변 바이트 배열은 bytearray() 내장 함수를 이용해서 생성한다. byte() 내장 함수처럼 순서열을 매개 변수로 받아 가변 바이트 배열을 만들어낸다. 한번 사용해 보자.

>>> b = bytearray( b'123' ) #불변 바이트 배열로부터 가변 바이트 배열 만들기
>>> b[0]
49
>>> b[0] = 54 # 첫 번째 원소에 '6' 쓰기
>>> b
bytearray(b'623')

여기까지가 내가 오늘 불변/가변 바이트 배열에 대해 공부한 전부다. 마지막으로 가변 바이트 배열의 메소드를 몇 가지 테스트 하는 것으로 오늘 일기를 마감해야겠다.

>>> b = bytearray( b'123' )
>>> b
bytearray(b'123')
>>> b.append ( 99 ) # 가변 바이트 배열에 덧붙이기.
>>> b
bytearray(b'123c')
>>> b.index( b'23' ) # 일치하는 바이트 배열 찾기
1
>>> b.replace( b'23', b'ab' ) # '23'을 'ab'로 바꾸기
bytearray(b'1abc')
>>> b.remove ( ord('1') ) # '1'을 찾아 제거하기
>>> b
bytearray(b'abc')

저작자 표시 비영리 변경 금지
Posted by seanlab

Trackback Address :: http://www.seanlab.net/trackback/14 관련글 쓰기

댓글을 달아 주세요

순서열의 세부 자료형인 튜플과 리스트는 서로 닮은 꼴인 자료형이다. 하지만 서로의 성질은 완전히 반대이다. 튜플은 불변 객체고, 리스트는 가변 객체이기 때문이다. 튜플은 완전히 새로 할당하지 않는 한 객체의 일부를 변경하는 것이 불가능하다. 리스트는 가능한데 말이다.

튜플은 둥근 괄호( '('와 ')' )를 이용해서 선언할 수도 있고, tuple() 내장 함수를 이용할 수도 있다.

예를 들어 보자. 먼저 둥근 괄호를 이용해서 튜플을 만들어 보자.

>>> t = (1, 2, 3)
>>> t
(1, 2, 3)
>>> type(t)
<class 'tuple'>

앞에서도 이야기했지만 튜플은 읽기만 가능하고 쓰기(변경)는 허용되지 않는다. 쓰기를 시도해봤더니 인터프리터가 에러를 내뱉는다.

>>> t[0]
1
>>> t[1]
2
>>> t[1] = 4
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
t[1] = 4
TypeError: 'tuple' object does not support item assignment

자, 이번엔 tuple() 내장 함수를 보자. 이 놈은 쓸모가 많다. 문자열도, 리스트도, 튜플도 다 튜플로 만들어준다.

우선 문자열.

>>> tuple( '123' )
('1', '2', '3')
>>> tuple( '홍길동')
('홍', '길', '동')

잘된다. 이젠 리스트하고 튜플로부터 튜플을 만들어 보자. tuple() 함수를 이용하면 된다.

>>> tuple ( ( 1, 2, 3 ) )
(1, 2, 3)
>>> tuple ( [ 1, 2, 3 ] )
(1, 2, 3)

리스트는 변경이 가능한 순서열이다. 현재 있는 내용에 덧붙일 수도 있고(append), 끼워넣을 수도 있고(insert), 일부를 없앨 수도 있다(remove).

>>> l = [ 1, 2, 3 ]
>>> l.append( 4 )
>>> l
[1, 2, 3, 4]
>>> l.insert(3, 3.5)
>>> l
[1, 2, 3, 3.5, 4]
>>> l.remove(3.5)
>>> l
[1, 2, 3, 4]

리스트에는 정렬(sort), 뒤집기(reverse) 등의 기능도 있다.

>>> l = [ 1, 3, 4, 2 ]
>>> l.sort()
>>> l
[1, 2, 3, 4]
>>> l.reverse()
>>> l
[4, 3, 2, 1]

한편, 리스트는 [와 ] 사이에 원소를 나열해서 생성할 수 있지만, list() 내장 함수를 이용하는 것도 가능하다. list() 함수는 tuple() 함수처럼 다른 순서열로부터 리스트를 만들어 준다.

>>> l = list( (1, 2, 3) )
>>> l
[1, 2, 3]
>>> l = list( [1, 2, 3] )
>>> l
[1, 2, 3]
>>> l = list ( '123' )
>>> l
['1', '2', '3']

이쯤이면 튜플과 리스트에 대해 대강은 이해한 것 같다. 마지막으로 'Reverse'라는 문자열을 뒤집는 테스트 코드를 만들어 보고 오늘은 일기를 끝내야겠다.

>>> l = list( 'Reverse' )
>>> l.reverse()
>>> s = ''.join( l )
>>> s
'esreveR'

저작자 표시 비영리 변경 금지
Posted by seanlab

Trackback Address :: http://www.seanlab.net/trackback/13 관련글 쓰기

댓글을 달아 주세요

뇌를 자극하는 알고리즘 탈고 준비로 파이썬 공부에 소홀했다. 스케줄 조정을 잘해야 꾸준히 잘할 수 있을 텐데 쉽지 않을 것 같다.

아무튼 이제 문자열을 보자. 순서열이 제공하는 기능만으로도 대부분의 문자열 처리가 가능할 것 같다. 하지만 파이썬은 여기에 그치지 않고 각 문자열을(뿐만 아니라 다른 세부 자료형들도) 사용하기 쉽게 설계를 해놓았다. 다음 표는 문자열(str) 클래스에서 제공하는 메서드 목록이다. 자주 사용할 것으로 예상되는(기준 : 내맘) 같은 메서드는 굵게 표시를 해뒀다.

메서드

설명

str.capitalize()

첫 문자를 대문자로 변환

str.center(width[, fillchar])

>>> s = "center"
>>> s.center( 15 )
' center '

str.count(sub[, start[, end]])

sub가 문자열 안에 몇 개 들어 있는지 계수

str.encode([encoding[, errors]])

특정 인코딩으로 인코드함. 예를 들어 ASCII를 UNICODE로 변경하는 것이 가능함.

str.endswith(suffix[, start[, end]])

문자열이 suffix로 끝나는지의 여부를 반환

str.expandtabs([tabsize])

문자열 내의 탭을 tabsize길이의 스페이스로 변환한다.

str.find(sub[, start[, end]])

문자열 내에서 sub가 위치한 곳을 찾는다. 없으면 –을 반환한다.

str.format(format_string, *args, **kwargs)

프로그래머라면 이 기능부터 찾아봤을 것이다. 문자열 포맷을 수행한다.
>>> name = "My name is {0}"
>>> name.format( "Sean" )
'My name is Sean'

str.index(sub[, start[, end]])

find와 같다. 찾는 문자열이 없으면 ValueError를 올리는 것만 빼고.

str.isalnum()

문자열이 알파벳과 숫자만으로 이루어져있는지 판단

str.isalpha()

문자열이 알파벳만으로 이루어져있는지 판단

str.isdecimal()

10진수인지 판단

str.isdigit()

숫자인지 판단

str.isidentifier()

식별자인지를 판단
>>> 'id'.isidentifier()
True

str.islower()

모든 글자가 소문자인지를 판단

str.isnumeric()

숫자인지를 판단

str.isprintable()

인쇄가능한지를 판단(인쇄 불가능한 문자가 포함되어 있으면 False를 반환)

str.isspace()

스페이스로만 되어있는지를 판단

str.istitle()

각 어절의 첫 글자가 대문자이고 뒤따라오는 문자들은 소문자인 Title 화되어 있는지 판단

예)
>>> 'good morning.'.istitle()
False
>>> 'Good morning.'.istitle()
False
>>> 'Good Morning.'.istitle()
True

str.isupper()

모든 글자가 대문자인지를 판단

str.join(seq)

>>> ','.join('abc')
'a,b,c'

str.ljust(width[, fillchar])

>>> 'abc'.ljust(10)
'abc '

str.lower()

모든 글자를 소문자로 변환

str.lstrip([chars])

>>> ' spacious '.lstrip()
'spacious '
>>> 'www.example.com'.lstrip('cmowz.')
'example.com'

str.maketrans(x[, y[, z]])

  

str.partition(sep)

>>> 'abcdefg-hjklmn'.partition('-')
('abcdefg', '-', 'hjklmn')

str.replace(old, new[, count])

>>> '123456789'.replace('123', 'ABC')
'ABC456789'

str.rfind(sub[, start[, end]])

찾는 문자열이 없으면 -1 반환
>>> 'ABC456789'.rfind('67')
5

str.rindex(sub[, start[, end]])

찾는 문자열이 없으면 ValueError 예외 발생
>>> 'ABC456789'.rindex('67')
5

str.rjust(width[, fillchar])

>>> 'abc'.rjust(10)
' abc'

str.rpartition(sep)

>>> 'ABC-DEF-GHI'.rpartition('-')
('ABC-DEF', '-', 'GHI')

str.rsplit([sep[, maxsplit]])

>>> 'ABC-DEF-GHI'.rsplit('-')
['ABC', 'DEF', 'GHI']

str.rstrip([chars])

>>> ' 123 '.rstrip()
' 123'

str.split([sep[, maxsplit]])

>>> 'ABC-DEF-GHI'.split('-')
['ABC', 'DEF', 'GHI']

str.splitlines([keepends])

>>> 'ABC\nDEF\nGHI'.splitlines()
['ABC', 'DEF', 'GHI']

str.startswith(prefix[, start[, end]])

>>> '123456'.startswith('456')
False
>>> '123456'.startswith('123')
True

str.strip([chars])

>>> ' 123 '.strip()
'123'

str.swapcase()

>>> 'My name is Sean.'.swapcase()
'mY NAME IS sEAN.'

str.title()

>>> 'good morning.'.title()
'Good Morning.'

str.translate(map)

  

str.upper()

>>> 'abc'.upper()
'ABC'

str.zfill(width)

>>> '123'.zfill(10)
'0000000123'

파이썬은 확실히 다른 언어보다 더 나은 편의를 제공한다. 과연 공공연하게 '편리한 언어'라고 광고해도 괜찮아 보인다. 파이썬으로 문자열을 다루다가 C로 문자열을 다루려면 적응이 잘 안될 것 같다. 다음에는 문자열의 형제들, 즉 다른 순서열들에 대해 알아볼 계획이다.

저작자 표시 비영리 변경 금지
Posted by seanlab

Trackback Address :: http://www.seanlab.net/trackback/12 관련글 쓰기

댓글을 달아 주세요

사전에서 Sequence를 찾아보면 순서, 연속물 이런 뜻으로 나온다. 파이썬의 Sequence는 이런 뜻으로는 설명이 어렵다. 누군가 이것을 이 바닥 용어로 적절하게 의역했다. "순서열"이다. C/C++/C# 또는 Java 경험이 있다면 순서열이 배열과 비슷하고 생각하면 된다. 아니, 비슷하다는 표현이 적절하지 않은 것 같다. 생김새는 비슷하지만 사용하기는 더 쉽고 더 강력한 기능을 제공하기 때문이다.

한편, 파이썬의 순서열 밑에는 여러 세부 자료형들이 존재한다. 순서열은 불변 순서열과 가변 순서열로 구분 되는데, 불변 순서열에는 문자열(String), 튜플(Tuple), 불변 바이트 배열이 있고 가변 순서열에는 리스트, 가변 바이트 배열이 있다. 종류가 6가지나 된다. 하지만 걱정하진 않아도 될 것 같다. Numeric이 그랬던 것처럼 같은 범주 안에 있는 자료형들은 대부분의 속성들을 공유하기 때문이다. 순서열의 기본 속성을 문자열을 통해 알아보자.

문자열을 선언하는 방법은 작은 따옴표(')나 큰 따옴표(")의 짝으로 문자열을 감싸는 것이다. 다음과 같이 말이다.

>>> s = "This is a string."
>>> t = 'This is a string, too.'
>>> s
'This is a string.'
>>> t
'This is a string, too.'
>>> type(t)
<class 'str'>
>>>

파이썬의 문자열은 문자의 집합이기 전에 순서열임을 잊지 말자. 순서열은 두 순서열을 결합하는 + 연산자를 제공한다. 따라서 순서열의 세부 자료형인 문자열도 + 연산자를 이용하여 두 문자열을 결합할 수 있다.

>>> hello = "Hello"
>>> world = ", World"
>>> hello_world = hello + world
>>> hello_world
'Hello, World'

순서열은 + 연산자 뿐만 아니라 쓸모가 많은 여러 연산자를 지원한다. 다음 코드에 그 예가 있다.

>>> s = 'Hello, World.'
>>> s[3:5]         # s의 3번째부터 5번째까지 자르기(Slicing)
'lo'
>>> 'o' in s         # 'o' 가 순서열 s 안에 들어 있는가
True
>>> 'x' in s         # 'x' 가 순서열 s 안에 들어 있는가
False
>>> s * 3        # 순서열 s를 3번 복사해 붙여 넣기
'Hello, World.Hello, World.Hello, World.'
>>> s[8]         # 8번째 문자
'o'
>>> len(s)         # s의 길이
13
>>> min(s)         # s의 최소값
' '
>>> max(s)         # s의 최대값
'r'

파이썬을 사용하다가 다시 C나 Java를 사용하게 되면 답답해질 것 같아 벌써부터 걱정이 든다. 기존에 다뤄봤던 언어에서 제공하던 배열에 비해 훨씬 유연하고 강력하다. 그 중에서도 특히 자르기(slicing)가 아주 백미다. 그런데 자르기라고 하니 용어가 쉽게 와 닿지 않는다. 그냥 슬라이싱이라고 해야겠다.

앞에서는 매개 변수를 한 개, 두 개만 넣었지만 슬라이싱은 원래 아래와 같이 세 개의 매개 변수를 받는다.

[시작인덱스, 종료인덱스, 보폭(step)]

보폭이 왜 필요한지 잘 이해가 안됐는데 실제로 사용해보니까 상당히 쉽다.

>>> s = 'Hello, World.'
>>> s[0:len(s):1] #0번부터 문자열의 끝까지 1개의 요소마다 1개를 골라 슬라이싱
'Hello, World.'
>>> s[0:len(s):2] #0번부터 문자열의 끝까지 2개의 요소마다 1개를 골라 슬라이싱
'Hlo ol.'
>>> s[0:len(s):3] #0번부터 문자열의 끝까지 3개의 요소마다 1개를 골라 슬라이싱
'Hl r.'
>>> s[0:len(s):4] #0번부터 문자열의 끝까지 4개의 요소마다 1개를 골라 슬라이싱
'Hoo.'
>>> s[0:len(s):20] #0번부터 문자열의 끝까지 20개의 요소마다 1개를 골라 슬라이싱

그러고 보니 아까 예로 사용했던 s[3:5]는 s[3:5:1]을 줄인 표현이었다. s[8]은 s[8:8:1]을 줄인 표현이고 말이다. 슬라이싱은 아주 유연하다. 다음과 같이 앞/뒤 매개 변수를 생략해서 사용할 수도 있다.

>>> s = 'Hello, World.'
>>> s[:5]         #s[0:5:1] 과 같음
'Hello'
>>> s[7:]        #s[7:len(s):1] 과 같음
'World.'

재미있다. 이제 겨우 자료형을 공부해 나가고 있는 중인데 문법이 손에 착 감기는 느낌이다. 다음에는 순서열의 세부 자료형들을 차근차근 살펴봐야겠다.

저작자 표시 비영리 변경 금지
Posted by seanlab

Trackback Address :: http://www.seanlab.net/trackback/11 관련글 쓰기

댓글을 달아 주세요