검색결과 리스트
이해에 해당되는 글 1건
- 2012.01.08 파이선을 이해하는데 도움이 되는 퀴즈
글
파이선을 이해하는데 도움이 되는 퀴즈
퀴즈 : http://openlook.org:625/blog/2008/02/27/cb-1206/
얼마 전에 "사랑하지 않으면 떠나라"의 서평 제목으로는 좀 독특한 "당신은 자바 가상 머신을 죽일 수 있나요?"라는 글을 보고 떠올라서, 혹시 파이썬을 쓰다가 발생하는 문제를 얼마나 잽싸게 해결하고, 문제가 생길만한 코드를 짜지 않는 등 이해정도와 관련된 것을 시험해 볼 수 있는 문제를 한 번 내 봤습니다. -ㅇ-;; 물론 제가 냈기 때문에 제가 아는 한에서만 나온거라 좀 편향돼 있을 수도 있지만.. 그냥 재미로 한 번;;
1. 다음 파이썬 타입 중에서 "일반적으로" 큰 수를 다룰 수 있는 순서대로 정렬하세요. decimal.Decimal int/long float (inf 제외) str (36진법으로 풀어 쓴다) 2. 다음 파이썬 타입 중에서 해시가 불가능한 타입을 모두 고르세요. unicode float set decimal.Decimal dict 3. 다음 중 최대 메모리 사용량이 가장 많은 코드를 고르세요. (ㄱ) max([i for i in range(1000)]) (ㄴ) max([i for i in xrange(1000)]) (ㄷ) max(i for i in range(1000)) (ㄹ) max(i for i in xrange(1000)) 4. 부모 클래스에서 __x(self) 메쏘드가 있을 때, 자식 클래스에서 부모 클래스가 정의된 소스코드를 수정하지 않고 호출할 수 있는 방법을 가능한 한 다양한 방법으로 쓰세요. 5. pymalloc을 넣고 컴파일했을 때 발생하는 현상이 아닌 것은? (ㄱ) 할당한 메모리보다 더 많이 할당된다. (ㄴ) 같은 루틴을 반복할 경우 메모리가 샐 수도 있다. (ㄷ) 할당된 객체가 쓰는 메모리를 해제해도 남아있을 수도 있다. (ㄹ) 메모리 할당이 더 느려질 수도 있다. 6. 다음 중 메모리 할당 횟수가 가장 많은 코드는? (ㄱ) map(int, range(100)) (ㄴ) map(str, range(100)) (ㄷ) map(long, range(100)) (ㄹ) map(unicode, range(100)) 7. exec "x ** y" 를 실행 할 때 발생할 수 있는 예외가 가장 아닐 "것 같은" 것은? NameError OverflowError MemoryError TypeError RuntimeError TabError ZeroDivisionError 8. 모듈을 들여오는 과정과 관련된 모듈 또는 객체가 아닌 것을 고르세요? (파이썬 2.x 기준) sys.path zipfile imp warnings marshal sys.modules __future__ 9. x += x 했을 때 할당된 메모리 크기가 변하지 않을 수도 있는 초기 x 값을 모두 고르세요? (ㄱ) sys.maxint (ㄴ) [1, 2] (ㄷ) 'guido' * 10 (ㄹ) True (ㅁ) sys.version 10. 다음 중 키보드 입력(ctrl-c)으로 중단할 수 있는 것를 모두 고르세요? (ㄱ) select.select (ㄴ) 9 ** 9999 (ㄷ) os.listdir (ㄹ) Decimal(9) ** 9999 (ㅂ) deque().add 11. CPython VM을 죽일 수 있는 파이썬 코드를 3가지 방법 이상 작성해 보세요. 12. 다음 중 오버라이딩으로 동작을 "바꿀" 수 있는 경우를 모두 고르세요? (ㄱ) not A (ㄴ) A is B (ㄷ) A = B (ㄹ) A != B (ㅁ) A <- B (ㅂ) A and B (ㅅ) A | B (ㅈ) (A, B) 13. 상속 받은 자식 클래스에서 단순하게 메쏘드를 오버라이드 했을 경우에도 베이스 클래스에서 "강제로" 자기 메쏘드를 부르게 하고 싶을 때 쓸 수 있는 방법 몇 가지? 14. gc.collect()가 해결할 수 없는 문제는? (ㄱ) 순환 참조 (ㄴ) C모듈의 전역 변수 (ㄷ) C객체의 멤버 변수 (ㄹ) C객체 간의 순환 참조 15. x += y를 실행했는데 ImportError가 발생했다. 어떤 상황일까? 가설을 5개 이상 생각해 보세요. 16. x = y를 실행했는데 TypeError가 발생했다. 어떤 상황일까? 가설을 2개 세워 보세요. 17. if list(x): raise SystemExit 했더니 프로그램이 종료했다. 어떤 상황일까? 가설을 5개 세워 보세요. 18. def x(a, b):에 대해서 x(1, 2)했는데 TypeError가 난다. 어떤 상황일까? 가설을 5개 세워 보세요. 19. import os; os.listdir('.') 했더니 AttributeError가 난다. 어떤 상황일까? 가설을 3개 세워 보세요. 20. print x하면 0인데 if x: print "Yay!" 하면 Yay!한다. 어떤 상황일까? 가설을 3개 세워 보세요.
답1 : http://mearie.org/journal/2008/02/inside-python-quiz
파이썬을 두루 이해하는 데 도움 되는(?) 퀴즈(퍼키의 열고 보는 세상)를 보고 한 번 풀어 본답시고 풀어 봤습니다. 맞는지는 저도 보장 못 합니다. -_-;
너무 많아서 일단 첫 열 문제만 풀어서 1편으로 나눕니다.
1번
역설적이게도 decimal.Decimal, int/long, str, float 순서.
float는 mantissa의 길이가 고정된 부동 소수점 값이라서 뒤로 밀립니다. int/long과 str 중에서는, int/long은 한 바이트의 7비트 이상(8비트는 아닌 걸로 기억하고 있음)을 활용하지만 str은 고작해야 log236 ≈ 5.2비트 밖에 못 쓰니까 int/long이 더 많은 정보를 담겠지요. decimal.Decimal은 float과 마찬가지로 mantissa의 길이가 (context에 따라) 고정되어 있지만, 대신 지수부를 마음대로 늘릴 수 있기 때문에 가장 큰 수를 저장할 수 있습니다.
참고로 int/long은 보통 10만자리를 넘으면 repr하기도 벅찹니다. 2진법으로 저장된 숫자를 10진법으로 변환하는 데 10만회의 나눗셈이 필요하거든요. FFT를 사용해서 변환하는 빠른 방법도 존재하긴 합니다만 파이썬에 이런 걸 기대하긴 무리인 듯.
2번
set과 dict.
일반적으로 변하지 않는 값(immutable)만이 해시가 가능하며, 따라서 dict나 set 등의 키값으로 쓰일 수 있습니다. 물론 멀쩡하게 생긴 클래스에 __hash__
메소드 집어 넣고 뻥을 치는 건 가능하긴 합니다만 이 클래스의 값을 바꿔 버리면 사전의 동작이 희한하게 변해 버릴테니 좋은 행동은 아니겠죠.
덤으로 만약 set을 해시 가능하게 만들려면 frozenset이라는 별도의 형을 써야 합니다.
3번
(ㄱ). 그 다음은 (ㄷ) 아니면 (ㄴ)인데 둘의 차이는 별로 크지 않아서 생략.
(ㄱ)은 range를 써서 임시 리스트를 하나 만들 뿐만 아니라 제너레이터가 아닌 리스트 해석을 써서 또 다른 리스트를 만들고 있습니다. 1000 크기의 리스트 두 개가 생기니 가장 많은 메모리를 먹을 수 밖에요.
4번
가장 쉬운 방법은 __x
메소드가 어느 클래스에 있는지 확인해서, 그 이름을 통해 바로 접근(예를 들면 _SuperClass__x
)하는 것이겠습니다.
만약 어느 클래스에 있는지 잘 모르겠다면, 그리고 object로부터 상속받은 (보통 new-style이라 불리는) 클래스라면, __mro__
속성을 사용해서 다음과 같이 참고해도 되겠습니다. 이 속성은 메소드를 검색하기 위해 뒤져 봐야 하는 클래스 객체들의 목록을 순서대로 나열한 것입니다.
def searchprivate(obj, method):
assert method.startswith('__')
for cls in type(obj).__mro__:
try: return getattr(obj, '_' + cls.__name__ + method)
except AttributeError: pass
return None
…더 이상 생각나는 게 없어서 쥐쥐.
5번
당장 생각하기에는 (ㄴ)이 가장 가능성이 없는 얘기 같습니다. 확신은 못 하겠고…
pymalloc의 작동 원리는 사실 간단합니다. 파이썬 객체들은 동적으로 할당되는 포인터들만 빼면 그다지 크지도 않은데 malloc의 부하(대부분의 malloc 구현은 아무리 작은 메모리라도 최소한 8바이트 내지 16바이트 정도의 공간을 내부 관리용으로 사용합니다.)를 참고 쓰기는 그렇죠. 그래서 같은 크기의 객체를 담을 공간을 적절히 많이 할당해 놓은 뒤, 필요할 때마다 그 메모리에 대한 포인터를 반환하는 식으로 할당을 처리하는 것입니다. 진실(?)을 말하자면, 이런 할당 정책은 pymalloc을 비롯한 많은 메모리 관리자들이 쓰고 있을 뿐만 아니라 몇몇 malloc 구현이 작은 메모리에 한해서 이렇게 하고 있기도 합니다. -_-;
따라서 한 객체만 생성해도 다른 비어 있는 공간(보통 arena라 부름)이 없으면 새로 큰 공간을 할당하게 되므로 (ㄱ)는 당연히 성립하고, 한 객체가 메모리를 해제한다 하더라도 arena에 다른 것들이 차 있으면 전체적으로는 메모리 해제가 불가능하니 (ㄷ)도 성립하겠습니다. (ㄹ)도 일말의 가능성은 있지만 그 특성상 한 객체만 생성해도 새로 큰 공간을 할당해야 할 때는 큰 비용이 필요할테니 (이래도 amortized cost는 일정합니다만) 일단 맞다고 칩시다.
(ㄴ)는 메모리가 샌다는 표현을 하고 있는데, 메모리가 새는 것은 메모리 관리자보다는 garbage collector의 책임이기 때문에 pymalloc의 문제라고 보기는 힘들 것 같습니다. 버그가 없다면 pymalloc은 적어도 아예 필요 없는 메모리를 해제 안 한 채 버리지는 않아야 합니다.
6번
당장 생각하기에는 (ㄹ)일 가능성이 큽니다. 다만 제가 파이썬 소스 코드를 잘 안 봐서 (ㄷ)일 수도 있습니다.
이 문제를 풀려면 파이썬의 기본 자료형들이 어떻게 구성되는지를 알아야 합니다. Fixnum만 특수한 처리를 하는 괴악한 방법을 쓰는 루비와는 달리, 파이썬은 모든 객체를 힙에 올려 버리되 너무 많이 쓰여서 닳아 없어질 것만 같은 객체들만 따로 캐싱을 해 두는 정책을 씁니다. 가장 흔한 예로 None 같은 내부 데이터형이나, -5부터 100까지(컴파일 설정에 따라 다를 수 있음)의 int 값들, 1바이트 문자열들 등이 포함됩니다.
따라서 (ㄱ)는 별도의 할당 없이 캐시된 객체를 반환하는 것으로 끝나고, (ㄴ)의 경우에도 몇몇 객체들은 캐시된 객체를 반환하게 되므로 답이 될 수 없습니다. (ㄷ)와 (ㄹ)에는 그러한 캐시 정책이 없습니다만, 제 생각에는 (ㄷ)도 작은 숫자(보통 int형으로 표현 가능할만한)에 대해서는 메모리를 덜 할당하는 정책을 쓰지 않을까 싶어서 (ㄹ)일 거라고 생각합니다.
7번
TabError입니다. 이게 만에 하나 나타난다면 파이썬 컴파일러가 아니라 파서가 틀린 겁니다. 각각의 예외에 대해 나타날 수 있는 가능성을 제시해 본다면:
- NameError는 x나 y가 존재하지 않는 변수일 때 발생합니다.
- OverflowError는 x나 y가 float이고, 그 결과가 너무 클 때 발생합니다. 다만 이 코드는 부동 소숫점 하드웨어 예외를 어떻게 설정했느냐에 따라서 그냥 inf를 반환할 수도 있습니다.
- MemoryError는 x나 y가 모두 int/long이고, 그 결과가 너무 클 때 발생합니다. 하지만 그렇게 자주 볼 수 있는 건 아니고, 보통은 쓰래싱(thrashing)이 일어나다가 malloc이 뻗거나 하는 상황에만 나오는 것 같습니다.
- TypeError는 x나 y 중 하나 이상이 수치형이 아닐 경우에 발생합니다.
- RuntimeError는 언제 발생할 지 감은 못 잡겠습니다만, 많은 수의 예외가 RuntimeError로부터 상속받으니 뭐 발생할 수도 있겠죠 뭐. (무책임)
- ZeroDivisionError는 x가 0이고 y가 음수이거나 복소수일 때 발생합니다.
TabError는 SyntaxError로부터 상속받아서, 코드의 들여쓰기에 탭이나 공백이 잘못 섞여 있을 때 나는 예외입니다. exec는 물론 이 예외를 낼 수 있습니다만 코드가 고정되어 있는 이상 그런 예외는 날 수가 없겠죠.
8번
warnings입니다. 다른 것들은 이리 저리 쓸 데가 있습니다:
- sys.path는 모듈을 검색할 때 사용할 경로들의 목록입니다.
- zipfile은 만약 sys.path에 zip 파일이 들어 있을 경우 그 안에 있는 모듈을 읽기 위해 사용합니다. py2exe 같은 것들이 이 기능을 자주 쓰죠.
- imp는 모듈을 들이는 내부 과정을 구현한 모듈입니다.
- marshal은 모듈을 들이고 코드 객체를 읽어 들이는데 사용합니다. pickle과 비슷한 역할입니다만 오로지(?) 파이썬의 내부 바이너리 포맷을 읽을 때만 쓰지요. 실제로 두 모듈은 지원하는 자료형들도 살짝 살짝 다릅니다.
- sys.modules는 모듈을 읽기 전에 이미 그 모듈을 들여왔는지 확인하기 위해서 사용되는 사전입니다.
__future__
(엄밀하게는from __future__ import
문)는 여지껏 파이썬에서 모듈을 읽는 데 사용되진 않았습니다만, 비교적 최근에 상대/절대 모듈 들여오기를 위한 확장이 추가되었기 때문에 답은 아닙니다.
9번
가장 그럴듯한 것은 (ㄹ)입니다. 구현에 따라서는 (ㄴ)도 답이 될 수 있습니다.
a += a
를 수행하면 자료형이 변해 버리는 (ㄱ)나 너무 길어서 어차피 재할당이 필요한 (ㄷ)는 답이 될 수 없고, (ㅁ)는 자료형이 변하지는 않지만 아쉽게도 파이썬에는 int.__iadd__
메소드가 없기 때문에 새로운 객체가 할당되긴 마찬가지입니다.
(ㄹ)의 경우 a += a
를 수행하면 a는 2가 되는데, 이 객체는 6번 답에서 설명했듯이 캐시되기 때문에 새로운 할당이 일어나지 않습니다. (ㄴ)는 보통 아닐 가능성이 높지만, 만약 파이썬 구현에서 리스트를 만들 때 처음으로 할당되는 크기가 최소 4라거나 하면 (STL 같은 일부 자료형 구현체들이 이런 정책을 사용합니다. 8인 경우도 어쩌다 봤습니다.) 재할당이 일어나지 않을 수도 있기 때문에 일단 가능성은 열어 놓았습니다.
10번
못 풀고 쥐쥐쳤습니다. -_- 누가 좀 풀어줘요…
답2 : http://mearie.org/journal/2008/02/inside-python-quiz-2.ko
이전 글에 이어집니다. 뒷부분 열 문제인데 너무 많군요. 몇 문제는 시간이 없어서 풀다 만 것도 있으니 상상력으로 채워 보아요.
11번
가장 손쉽고 빠른 방법은 파이썬 2.5에 추가된 ctypes 모듈을 쓰는 것입니다.
import ctypes
ctypes.CFUNCTYPE(int)(0x12345678)()
물론 이러면 윈도에서는 WindowsError가 대신 나겠지만, 코드를 조금 꼬아 놓는다면 (예를 들어서 CreateThreadEx 따위에 이상한 함수 포인터를 걸어 놓는다거나) 큰 문제는 되지 않습니다. 근데 왜 WindowsError가 나냐고요? 윈도의 예외 처리(SEH) API는 세그폴트 난 것도 예외로 처리해서 아래로 내려 보내거든요. MS C++에서는 이 방법으로 세그폴트 추적도 가능합니다. (…)
조금 더 그럴듯한 방법은 파이썬의 내부 구조를 사용하는 것입니다. 그 중 가장 쓸만한 것이 코드 객체인데, 일단 코드 객체를 생성할 방법만 존재하면 파이썬 클라이언트를 죽이기 어렵지 않기 때문에 특히 인클봇-_- 같이 파이썬 코드를 외부에서 실행할 수 있는 프로그램에서는 주의해야 합니다.
import types
types.FunctionType(types.CodeType(0,1,0,0,'d\0S',(0,),(),(),'','',0,''),{})()
위 코드는 바이트코드가 사용할 스택의 크기를 일부러 작게 잡아 줘서 세그폴트를 내는 예입니다. 파이썬 바이트코드는 스택 기계를 기반으로 하는데, 코드 객체에는 이 기계에 있는 최대 스택의 크기를 지정하는 항목이 있습니다. 위에서는 적어도 한 칸의 스택 공간(LOAD_CONST 때문에)이 필요한 바이트코드를 스택 공간이 없이 실행해서 프로그램이 망해 버립니다. 그 외에 잘못된 바이트코드를 쓰는 방법도 가능하겠습니다.
마지막 방법은 스택을 강제로 오버플로우 나게 만드는 것입니다. 이것도 어렵진 않군요.
import sys
sys.setrecursionlimit(99999999)
(lambda f=(lambda f:f(f)):f(f))()
파이썬은 내부적으로 재귀 호출의 한도를 두고 있기 때문에 일부러 이 과정을 따라하려면 먼저 재귀 호출 한도를 높여야 합니다. 파이썬의 함수 호출은 시스템 스택을 소모하면서 일어나기 때문에 재귀가 깊으면 시스템 스택을 모두 써 버릴 수도 있거든요. 스택리스 파이썬과 같은 다른 구현체는 이런 문제가 없습니다.
번외편으로 모로 가도 파이썬만 죽이면 된다는 신념을 실행하는 다음 코드도 참고하면 좋습니다. 윈도에서 돌아가는지 모르겠습니다.
import os, signal
os.kill(os.getpid(), signal.SIGSEGV) # 세그폴트 난 척 하기
12번
(ㄹ), (ㅁ), (ㅅ)이며, 해당하는 메소드는 각각 __ne__
, __le__
, __or__
입니다. (ㄱ)와 (ㅂ)도 __nonzero__
메소드를 통해 동작을 바꿀 수 있긴 하지만 완전히 다른 연산자로 동작하게 할 수는 없습니다.
13번
당장 생각할 수 있는 방법은 __getattribute__
를 오버라이딩해서 자식 클래스가 반환하는 묶인(bounded) 메소드를 덮어 씌우는 것입니다. 자식은 __getattribute__
를 다시 오버라이딩하지 않는 한 이 동작을 바꿀 수 없습니다.
import types
class Base(object):
def __getattribute__(self, name):
if name == 'method':
return types.MethodType(getattr(Base, name), self, Base)
raise AttributeError
def method(self, value=0):
return 42 + value
메타클래스를 사용하는 방법도 생각해 봤는데 생각대로 잘 되지 않아서 일단 쥐쥐.
14번
(ㄹ)입니다. 특히 __del__
메소드가 있는 클래스끼리 순환 참조가 일어날 경우 그렇습니다.
옛날 파이썬은 (ㄱ)에 해당하는 순환 참조도 제대로 처리하지 못 했습니다. 하지만 시간이 지나면서 정확한 순환 참조 체크 알고리즘이 구현되었고, 이제 대부분의 경우 파이썬은 정확히 garbage collection을 수행합니다. 하지만 만약 __del__
메소드가 있는 클래스끼리 순환 참조가 일어나면, 파이썬은 순환 참조를 끊으려 하지만 어느 __del__
을 먼저 수행해야 할 지 결정할 수 없기 때문에 암시적으로 참조를 끊지 않습니다. 대신 이 정보는 gc.garbage(아마도)에 저장되며, 프로그램은 명시적으로 순환 참조를 끊기 위해 이 리스트를 사용할 수 있습니다.
15번
x.__iadd__
를 수행하는 도중에 import를 시도하다 실패했을 경우.x.__iadd__
가 없고,x.__add__
를 수행하는 도중에 import를 시도하다 실패했을 경우.x.__iadd__
나x.__add__
를 얻기 위해x.__getattr__
을 수행하던 도중에 import를 시도하다 실패했을 경우.- x나 y가 coercion을 사용하고 (근데 이런 자료형은 별로 흔치 않습니다만)
x.__coerce__
를 수행하던 도중에 import를 시도하다 실패했을 경우. - 위에 언급한 모든 메소드들 중 하나가 import는 안 하고 일부러
raise ImportError
를 냈을 경우. (-_-;) - ImportError가 아닌 다른 이유(보통은 NameError겠지만)로 예외가 발생한 뒤, 사용자 정의 sys.excepthook에서 이 예외를 출력하려다가 ImportError를 발생시킨 경우.
- 대화형 인터프리터에서, sys.ps1이나 sys.ps2가 적절한 클래스로 설정되어 있고 어떠한 이유로 ImportError를 낼 경우.
- 파이썬 디버거나 쓰레드와 같이 외부 요인으로 인한 경우.
…물론 위에 열거한 것들 중 실제로 발생할 만한 것은 사실 별로 없습니다.
16번
쥐쥐. orz
17번
- x가 반복자를 가지고 있으며, 그 반복자가 바로 종료하지 않는 경우. 가장 가능성이 높습니다.
- list가 리스트 생성자가 아닌 다른 함수로 바뀌어서 거짓이 아닌 값을 반환하는 경우. 두 번째로 가능성이 높으며 보통 버그의 온상이 됩니다.
- list가 리스트 생성자가 아닌 다른 함수로 바뀌어서 그 안에서 프로그램을 종료해 버리는 경우.
- x가 반복자를 가지고 있으며, 그 반복자가 수행되는 도중에 프로그램이 종료된 경우.
- x의 반복자를 얻으려
__iter__
메소드를 수행하던 도중에 프로그램이 종료된 경우.
18번
- 당연하지만, 함수 x 안에서 TypeError를 발생시켰을 경우.
- 함수 x에 딸린 데코레이터가 있고, 데코레이터가 반환한 함수(x처럼 보이긴 하지만)가 TypeError를 발생시켰을 경우.
- x를 선언한 이래 x가 뭔가로 다시 덮어 씌워져서 호출 불가능한 값이 되었을 경우. 함수 이름이 x이면 그럴 법도 하죠.
…세 개 말고는 잘 모르겠습니다.
19번
__import__
가 선언되어 있고, 그 안에서 AttributeError를 발생시켰을 경우.__import__
가 선언되어 있지만 listdir이 존재할 리가 없는 잘못된 모듈을 반환하였을 경우. (예를 들어 os.py라는 모듈이 있을 때 무작정 불러 올 경우)
마지막 한 가지는 잘 모르겠는데, 아마 파이썬의 내부 설정에 따라 달라질 수 있는 경우가 있을 것 같습니다. -.-
20번
- x가 사실 int가 아니라 뭔가 다른 클래스라서 repr하면
'0'
이 나오는데__nonzero__
는 True를 반환하는 경우. - 같은 상황이지만,
x.__nonzero__
가 수행되는 도중에 출력이 일어날 경우. (이 경우 이 메소드는 False를 반환해야 합니다) print x
를 실행한 시점에 Yay!가 이미 찍혀 있지만 버퍼가 아직 flush가 안 되어 있어서 화면에 보이지 않을 경우. (터미널이 이상하다거나 sys.stdout이 바뀌어 있다거나 bufsize가 바뀌었거나 등등) 이 경우 뒤에 뭔가 flush를 할 수 밖에 없게 만드는 코드가 더 있어야 겠지요.- 사실 숫자 0이 아닌 대문자 O일 지도 모릅니다. 이럴 때는 터미널 글꼴을 바꾸면 만사 오케이.
'프로그래밍 > Python' 카테고리의 다른 글
python 파일 용량 확인 (0) | 2013.11.19 |
---|---|
ubuntu python mysqldb 설치 (0) | 2013.11.18 |
python setuptools 설치 (0) | 2013.09.20 |
python 스택 사이즈 수정 (0) | 2012.01.08 |
python 명령 인자 받아쓰기 (0) | 2011.12.09 |