Sunday, October 3, 2010

python 1부 : 문법 2

1부의 내용이 너무 길어지는 바람에 포스팅을 나누기로한다. 
책을 4장까지 밖에 보지 않았지만 지금까지 느낀점을 이야기 하자면 이 책의 포지션이 좀 애매하다는 것이다. 컴퓨터 언어를 전혀 모르는 이를 위해 쓴거 같지도 않고 그렇다고 심화해서 좀더 깊이 설명한것도 아니고 어중간하게 설명한다는 점이다. 글을 보다 보면 C를 알고 있다는 전제 하에 설명한거 같은데 그렇다고 뚜렷하게 각각의 요소를 C의 구성요소로 어떻게 만들었는지 설명하는 것도 아니고.. 애매하다. 


C로 만들었다고 하는데 객체 개념이 어떻게 들어갔는지, C++도 C로 만들은 것인지 그렇다면 궁극적으로 C는 무엇으로 만들었는지(어셈블리어라고 생각하고 있지만)등의 궁금증이 생긴다. 이것 또한 저자한테 질문을 해봐야 겠다. 어제 토요일 늦게 질문을 올렸는데 월요일에 답변이 오지 않으면 왠지 실망할거 같은 느낌이다.


chapter5 : 클래스
클래스의 선언은 함수의 선언과 유사하게 def 대신 class 키워드를 사용하면 된다. 클래스가 선언과 동시에 클래스 객체가 생성된다(클래스 이름의 이름 공간이 생긴다). 클래스를 사용하기 위해선 인스턴스 객체를 생성해야 한다. class MyClass:Name='shkm';def Print(self):print(self.Name) 이라는 클래스가 있으면 p1 = Myclass()와 같이 인스턴스 객체를 만들게 되고 이는 클래스의 객체와 모든 멤버변수와 멤버함수를 공유하게 된다. 다만 인스턴스 객체의 멤버변수가 변하게 되면 (p1.Name='eykang') 변경된 내용을 인스턴스 객체 이름 공간에 저장하게 된다.
클래스의 멤버변수,함수들은 default로 public으로 정의 된다. 위의 Myclass 에서 보면 self가 나오는데 이는 C++의 this와 같은 역할(자기 자신을 가르키는 포인터)을 한다. 이 self는 예약어는 아니지만(곧 다른 이름으로 표현 가능) 관행상 self라고 하며 '정적메소드'와 '클래스메소드'를 제외한 메소드의 첫번째 매개변수는 self로 취급된다.
그럼 self로 메소드를 나타내야 하는 이유? 인스턴트 객체도 클래스 객체의 메소드를 가리키고 있기 때문에 메소드를 사용하기 위해서는 자기 자긴을 가르키는 포인터를 넘겨줘야 한다. 그러나 그 메소드를 실행할때는 p1.Print() 처럼 정작 self에 대한 매개 변수를 넘겨주지 않는데 이는 자동적으로 self가 들어가게 된다. 이와 같은 호출을 바운드 메서드 호출이라 한다.
파이썬에서는 실행시간에 각 클래스와 인스턴스 이름 공간에 멤버 변수를 추가하거나 삭제할 수있다. 이는 서로 이름 공간이 분리 되어 있기 때문이라고 이해하면 된다. 클래스 객체에 새로운 멤버 변수를 추가하면 이는 인스턴스 객체에서 참조할수 있는데 이는 객체에서의 멤버 변수 탐색이 인스턴스>클래스>전역 순이기 때문에 자기 자신에 없는 멤버변수라도 클래스 객체에 생기면 참조할수 있는 것이다. 반면에 인스턴스 객체에 새로운 멤버변수를 추가하게 되면 자기 자신의 인스턴스 객체에서만 참조가 가능하다. 인스턴스 객체 내의 내장 속성 __class__를 이용하면 클래스 객체의 멤버변수를 바꿀수도 참조 할수도 있다.
한 클래스가 다른 클래스의 상속인지 확인하거나 한 인스턴스 객체가 어떤 클래스로부터 생성되었는지 확인하기 위해 isinstance(인스턴스 객체, 클래스 객체) 를 이용할 수 있다.
클래스 생성시 객체를 초기화 하기 위해 생성자가 파이썬 역시 있으며 이는 __init__() 멤버함수이다. 소멸자는  __del__() 이다. 생성자는 인스턴스 객체 생성시 호출되면 소멸자는 인스턴스 객체의 참조 카운트가 0이 될때 호출된다.
정적 메서드 : 원래 클래스의 멤버 함수를 사용하기 위해서는 인스턴스 객체를 생성하고 그것을 통해서 가능한데(그렇기 때문에 이러한 멤버 함수는 반드시 인자로 self가 있어야 한다) 인스턴스 객체 없이 클래스를 통해 직접 호출할수 있는 맴버 함수를 static method라고 한다(객체를 통하지 않기때문에 self 매개변수가 필요 없다).
클래스 메서드 : 클래스 메서드는 정적 메서드와 동일하나 단 암묵적으로 클래스를 첫 인자로 받는다.
파이썬에서 클래스는 기본적으로 public의 속성인데 멤버 변수 이름 앞에 __를 붙이면 private가 된다.
클래스의 연산자 오버로딩을 위한 멤버 함수들이 있다(책 참조).
인스턴스 객체의 멤버 변수 정보를 알려면 인스턴스 객체.__dict__을 이용하면 된다.
클래스 객체.__bases__ 는 클래스 객체의 직계 base 클래스를 알 수 있다.
파이썬에서는 base 클래스의 생성자를 이용하려면 derived 클래스의 생성자 내에 명시적으로 base 클래스를 언바운드 메서드 호출(self 인자를 넘겨주면서 호출하는 것)을 해야 한다.
C++에서는 method overriding 하기 위해서는 base 클래스의 함수와 derived 클래스의 함수가 이름, 매개변수, 리턴값이 같아야 하나 python에서는 함수 이름만 같아도 된다.
책에는 안나온 내용이지만 클래스 내에 함수 overloading은 python에서 안되는 것 같다. 그러나 *argv 나 **argv 나 기본적으로 python 자체가 각 자료형에 맞게 polymorphism이 이뤄진다는 걸생각하면 C++의 함수 overloading의 문법이 아니라도 의미적으로 가능하다.
클래스 객체.__mro__ 라고하면 상속 구조 속에 이름을 찾는 순서가 튜플로 나타내어진다.
다중 상속일 때 derived 클래스에서 base 클래스의 생성자를 호출할경우 중복 호출이 일어 날수 있는데 이러한 일을 방지 하기 위해 super() 내장함수를 이용한다(super().__init__(self)).

chapter6 : 모듈
모듈 이란? 여러코드를 한데 묶어 다른 곳에서 재사용 할수 있는 코드 모음(보통 비슷한 기능을 하는 함수나 큰 기능을 수행하는데 필요한 일련의 함수와 데이터가 포함)
dir(모듈) 하면 모듈 내의 함수, 데이터의 종류를 볼수 있다.
모듈의 정보 : http://docs.python.org/release/3.0.1/library/index.html
python의 모듈 경로 찾기 :  1.현재 디렉토리 2.PYTHONPATH 3.표준라이브러리디렉토리 , 위의 경로들은 sys.path에서볼수 있으며 추가도 가능하다.
import 문은 어디서나 가능, 심지어 함수 안에서 조차.
from <모듈> import * 하면 __로 시작하는 모듈안의 어트리뷰트 (함수와 데이터)를 제외한 모든 어트리뷰트를 이름 공간에 임포트 합니다.
모듈 reload를 위해 import imp; imp.reload(<모듈>).
모듈도 객체이다. 곧 모듈이 import가 되면 메모리에 로딩되면서 레퍼런스를 전달해 준다.
모듈의 __name__ 속성은 자신이 모듈로 쓰이면 모듈 이름이, 자신이 main 프로그램으로 직접 호출이 되면 __main__을 리턴한다.
관련있는 여러개의 모듈을 묶은 것을 패키지라고 한다. 패키지 디렉토리 안에는 여러 모듈 디렉토리와 함께 __init__.py 파일이 있는데 이는 패키지가 import 될때 실행되는 파일이다. __init__.py 파일 안에 __all__ 속성은 form import * 을 실행할때 포함할 하위 패키지의 목록이다. 상위 패키지를 import  했다고 해서 하위 패키지가 import 되는 것이 아니다. 하위 패키지의 모듈을 사용하기 위해서는 반드시 하위 패키지를 import 해야 한다.

chapter7 : 예외처리
프로그램의 제어 흐름을 조정하기 위해 사용하는 이벤트를 exception(예외)라고 한다.
이건 책 참조. 각종 내장 예외에 대한 것들.
try:
except:
finally:
raise 구문
assert 구문

chapter8 : 입출력
2.x 버젼에선 print는 함수가 아니였으나 3 버젼에서는 함수다.
locals(),vars(),globals() 함수는 지역변수들을 사전 형태로 반환한다.
open으로 파일 객체를 만들면 read(),readline(),readlines() 뿐만 아니라 seek()과 tell()함수도 제공된다.
seek() : 사용자가 원하는 위치로 파일 포인터를 이동
tell() :현재 파일에서 어디까지 읽고 썻는지 위치를 반환
with 구문을 이용하면 close()을 안해도 된다.
with open('test.txt') as f: print(f.readlines());print(f.cloased) 를 False 가 나오는데 위 구문을 마치고 f.closed로 확인해 보면 파일 객체인 f가 닫혀 있는걸 확인 할수 있다.
colors = ['red','green','black']이라는 변수가 있을때 이 내용을 그대로 파일에 넣고 나중에 읽었을때 그대로 리스트로 받을 수 있는데 이는 pickle이라는 모듈을 이용하면 된다.
import pickle; f= open('colors.txt','wb'); pickle.dump(colors,f); f.close(); del colors; f = open('colors.txt',rb); colors=pickle.load(f); f.close() 이렇게 하면 리스트 내용이 바이너리로 colors.txt 파일에 들어갔다가 고대로 pickle.load()로 읽어 들이면 바로 리스트로 입력이 된다(pickle을 이용할땐 반드시 바이너리 형식을 이용해야 한다). 이러한 pickle의 대상은 파이썬의 대부분의 객체가 가능하다(기본 자료형, 사용자 정의 클래스). 다만 pickle.dump로 사용자 정의 클래스를 파일에 바이너리로 저장했다가 다시 load로 읽어 들일때 그 클래스가 프로그램 내에 사전에 정의 되어 있어야 한다. 그렇지 않으면 AttributeError 발생

chapter9 : C/C++와 연동