diff --git a/.gitignore b/.gitignore index 1b593d6..6af2088 100644 --- a/.gitignore +++ b/.gitignore @@ -132,4 +132,6 @@ fabric.properties # https://plugins.jetbrains.com/plugin/8053-azure-toolkit-for-intellij .idea/**/azureSettings.xml -# End of https://www.toptal.com/developers/gitignore/api/pycharm,jupyternotebooks \ No newline at end of file +# End of https://www.toptal.com/developers/gitignore/api/pycharm,jupyternotebooks + +!8th_members/* diff --git a/8th_members/.gitkeep b/8th_members/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/10\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/10\354\243\274\354\260\250.md" new file mode 100644 index 0000000..6bff43e --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/10\354\243\274\354\260\250.md" @@ -0,0 +1,10 @@ +# 10주차 + +## 싱글 프로세스 + 싱글 스레드 +![alt text](week_10_single.png) + +## 싱글 프로세스 + 멀티 스레딩 +![alt text](week_10_multi_threading.png) + +## 싱글 프로세스 + 멀티 스레딩 (개수 제한) +![alt text](week_10_multi_threading2.png) \ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/11\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/11\354\243\274\354\260\250.md" new file mode 100644 index 0000000..ae232c3 --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/11\354\243\274\354\260\250.md" @@ -0,0 +1,79 @@ +# 11주차 + +## Set 내부 구조 살펴보기 +``` +PyTypeObject PySet_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "set", /* tp_name */ + sizeof(PySetObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)set_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + (reprfunc)set_repr, /* tp_repr */ + &set_as_number, /* tp_as_number */ + &set_as_sequence, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + PyObject_HashNotImplemented, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | + Py_TPFLAGS_BASETYPE, /* tp_flags */ + set_doc, /* tp_doc */ + (traverseproc)set_traverse, /* tp_traverse */ + (inquiry)set_clear_internal, /* tp_clear */ + (richcmpfunc)set_richcompare, /* tp_richcompare */ + offsetof(PySetObject, weakreflist), /* tp_weaklistoffset */ + (getiterfunc)set_iter, /* tp_iter */ + 0, /* tp_iternext */ + set_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)set_init, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + set_new, /* tp_new */ + PyObject_GC_Del, /* tp_free */ + .tp_vectorcall = set_vectorcall, +}; +``` + +``` +static void +set_dealloc(PySetObject *so) +{ + setentry *entry; + Py_ssize_t used = so->used; + + /* bpo-31095: UnTrack is needed before calling any callbacks */ + PyObject_GC_UnTrack(so); + Py_TRASHCAN_BEGIN(so, set_dealloc) + if (so->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *) so); + + for (entry = so->table; used > 0; entry++) { + if (entry->key && entry->key != dummy) { + used--; + Py_DECREF(entry->key); + } + } + if (so->table != so->smalltable) + PyMem_DEL(so->table); + Py_TYPE(so)->tp_free(so); + Py_TRASHCAN_END +} +``` +1. set 객체는 삭제될 때(destruction), set_dealloc 함수를 호출한다. +2. set_dealloc 함수는 가비지 컬렉터의 추적 대상에서 제외하고, 약한 참조 리스트를 클리어 하는 등의 작업을 한다. +3. 약한 참조 리스트를 클리어한다고 해서, 약한 참조 리스트에 포함되어 있는 다른 객체들의 메모리가 해제되는 것은 아니다. + diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/12\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/12\354\243\274\354\260\250.md" new file mode 100644 index 0000000..3aacba5 --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/12\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 12주차 + +## unittest 사용하기 +![alt text](week_12.png) \ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/13\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/13\354\243\274\354\260\250.md" new file mode 100644 index 0000000..5be9469 --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/13\354\243\274\354\260\250.md" @@ -0,0 +1,7 @@ +# 13주차 + +## pdb 실행해보기 +![alt text](week_13_debug.png) + +## CProfile 실행해보기 +![alt text](week_13_profile.png) \ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/1\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/1\354\243\274\354\260\250.md" new file mode 100644 index 0000000..ea89599 --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/1\354\243\274\354\260\250.md" @@ -0,0 +1,9 @@ +# 1주차 + +## CPython 소스코드 다운로드 및 환경 구성 + + +## 스터디에서 이루고 싶은 목표, 함께 하게 된 소감 +1. CPython internal 뿌셔뿌셔~! +2. 운영체제, 자료구조는 덤~! +3. 열심히 하겠습니다!! diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/2\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/2\354\243\274\354\260\250.md" new file mode 100644 index 0000000..a6bf541 --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/2\354\243\274\354\260\250.md" @@ -0,0 +1,5 @@ +# 2주차 + +## 문법 다시 생성하기 +`break` 대신 `bye`도 사용할 수 있도록 문법을 변경함. + \ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/3\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/3\354\243\274\354\260\250.md" new file mode 100644 index 0000000..684ea77 --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/3\354\243\274\354\260\250.md" @@ -0,0 +1,19 @@ +# 3주차 + +## [1] CPython 인터프리터 실행 과정 코드 레벨로 이해하기 + +
+ +
+ +## [2] 파이썬 세션에서 runtime flag 확인하기 + +
+ +
+ +## [3] `importlib.util.find_spec` 함수를 사용해서 원하는 모듈의 위치를 찾아보기 + +
+ +
\ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/4\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/4\354\243\274\354\260\250.md" new file mode 100644 index 0000000..6e46299 --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/4\354\243\274\354\260\250.md" @@ -0,0 +1,7 @@ +# 4주차 + +## instaviz로 AST 시각화 해보기 + + +## ‘거의 같음’ 연산자를 문법에 추가하고 AlE타입의 객체를 출력 해보기 + \ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/6\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/6\354\243\274\354\260\250.md" new file mode 100644 index 0000000..43c61ac --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/6\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 6주차 + +## 프레임 객체 생성하기 +![alt text](week_6.png) \ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/7\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/7\354\243\274\354\260\250.md" new file mode 100644 index 0000000..5e0f693 --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/7\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 7주차 + +## tracemalloc 모듈 사용해서 직접 메모리 확인해보기 +![alt text](week_7.png) \ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/8\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/8\354\243\274\354\260\250.md" new file mode 100644 index 0000000..e1820a3 --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/8\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 8주차 + +## sys.getrefcount 사용해보기 +![alt text](week_8.png) \ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/9\354\243\274\354\260\250.md" "b/8th_members/\352\263\240\353\217\231\355\235\254/9\354\243\274\354\260\250.md" new file mode 100644 index 0000000..ce074d8 --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/9\354\243\274\354\260\250.md" @@ -0,0 +1,11 @@ +# 9주차 + +## 싱글 프로세스 +![alt text](week_9_single.png) + +## 멀티 프로세스 +![alt text](week_9_multi.png) + +## 결론 +- 싱글: 1초 +- 멀티: 0.48초 \ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/main.py" "b/8th_members/\352\263\240\353\217\231\355\235\254/main.py" new file mode 100644 index 0000000..ec319ac --- /dev/null +++ "b/8th_members/\352\263\240\353\217\231\355\235\254/main.py" @@ -0,0 +1,8 @@ +import instaviz + +def hello(): + name = 'donghee' + text = 'hello ' + name + return name + +instaviz.show(hello) \ No newline at end of file diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_1.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_1.png" new file mode 100644 index 0000000..7621bb1 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_1.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_10_multi_threading.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_10_multi_threading.png" new file mode 100644 index 0000000..af3eac4 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_10_multi_threading.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_10_multi_threading2.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_10_multi_threading2.png" new file mode 100644 index 0000000..2aa7894 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_10_multi_threading2.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_10_single.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_10_single.png" new file mode 100644 index 0000000..10451c7 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_10_single.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_12.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_12.png" new file mode 100644 index 0000000..ff41905 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_12.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_13_debug.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_13_debug.png" new file mode 100644 index 0000000..5d87576 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_13_debug.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_13_profile.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_13_profile.png" new file mode 100644 index 0000000..9fcad16 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_13_profile.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_2.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_2.png" new file mode 100644 index 0000000..237381e Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_2.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_3_1.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_3_1.png" new file mode 100644 index 0000000..120b6b4 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_3_1.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_3_2.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_3_2.png" new file mode 100644 index 0000000..bb41135 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_3_2.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_3_3.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_3_3.png" new file mode 100644 index 0000000..18d20c3 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_3_3.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_4_1.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_4_1.png" new file mode 100644 index 0000000..febb846 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_4_1.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_4_2.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_4_2.png" new file mode 100644 index 0000000..f96920c Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_4_2.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_6.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_6.png" new file mode 100644 index 0000000..d494c76 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_6.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_7.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_7.png" new file mode 100644 index 0000000..68be964 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_7.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_8.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_8.png" new file mode 100644 index 0000000..025f80e Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_8.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_9_multi.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_9_multi.png" new file mode 100644 index 0000000..63d5b4b Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_9_multi.png" differ diff --git "a/8th_members/\352\263\240\353\217\231\355\235\254/week_9_single.png" "b/8th_members/\352\263\240\353\217\231\355\235\254/week_9_single.png" new file mode 100644 index 0000000..1ca06e4 Binary files /dev/null and "b/8th_members/\352\263\240\353\217\231\355\235\254/week_9_single.png" differ diff --git "a/8th_members/\352\271\200\354\204\234\355\230\204/1\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\204\234\355\230\204/1\354\243\274\354\260\250.md" new file mode 100644 index 0000000..b5930e7 --- /dev/null +++ "b/8th_members/\352\271\200\354\204\234\355\230\204/1\354\243\274\354\260\250.md" @@ -0,0 +1,8 @@ +### CPython 소스코드 다운로드 및 환경 구성 (화면 캡쳐) + + + +### 스터디에서 이루고 싶은 목표, 함께 하게 된 소감 등 + + - 잠시 놓았던 개발과 다시 친해지고 싶어요... + - 화이팅! diff --git "a/8th_members/\352\271\200\354\204\234\355\230\204/mission1.png" "b/8th_members/\352\271\200\354\204\234\355\230\204/mission1.png" new file mode 100644 index 0000000..7842f10 Binary files /dev/null and "b/8th_members/\352\271\200\354\204\234\355\230\204/mission1.png" differ diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/10\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/10\354\243\274\354\260\250.md" new file mode 100644 index 0000000..26e6439 --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/10\354\243\274\354\260\250.md" @@ -0,0 +1,12 @@ +# Port Scanner: Multi Threading 코드 실행해보기 +## 싱글 프로세스 + 싱글 스레드 +image +

+ +## 멀티 스레드 +image +

+ +## 멀티스레딩 + 스레드 개수 제한 +image +근소하게 개선됐다. \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/11\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/11\354\243\274\354\260\250.md" new file mode 100644 index 0000000..61eca46 --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/11\354\243\274\354\260\250.md" @@ -0,0 +1,30 @@ +# 원하는 Type 분석해보기: List 타입 +### 1. data structure of python list +![enter image description here](https://miro.medium.com/max/720/1*OJr_4YC6OMB30XQzvPmPkw.png) +![enter image description here](https://devocean.sk.com/CKFinderJava/userfiles/images/py%EA%B5%AC%EC%A1%B0.png) + ### Python list data structure +![enter image description here](https://miro.medium.com/max/720/1*l1O3TOk75WyRzrDn2bUe5A.png) + - PyListObject: python list의 C 구현체. + - PyObject_VAR_HEAD: 인스턴스마다 길이가 변하는 객체를 선언할 때 사용되는 macro. + - **ob_item: 이중 포인터 (리스트 원소들의 포인터 배열에 대한 포인터). 객체 주소들을 저장한다. + - allocated: 리스트에 할당된 크기 + - **Py__Object: 모든 클래스들의 조상인 PyObject를 상속받은 뒤 __에 type명(ex: int, var, list, array etc.)을 붙여 각 타입에 대한 파이썬 클래스를 구현. + +이에 의해 파생되는 특징들? + #### 1) 동적 타입 지원 +![enter image description here](https://devocean.sk.com/CKFinderJava/userfiles/images/image%282671%29.png) +한 연산 수행 중간중간에 type checking이 많아 정적 배열보다 동작 느림 + +#### 2) 크기가 가변적(동적) +처음에 크기를 작게 잡아뒀다 꽉 차면 list_resize 메서드를 작동시켜 크기를 늘려준다. (용어: 더블링) +→ 해당 작업 발생 시 정적 배열보다 동작 속도 느려짐 + +#### 3) 포인터를 이중으로 거침 +ob_items**의 특징에 의해 value를 바로 얻을 수 없어 속도 느림 + +#### 4) 캐시의 메모리 지역성 문제 +![enter image description here](https://computerscience.chemeketa.edu/cs160Reader/_images/Memory-Hierarchy.jpg) +![enter image description here](https://devocean.sk.com/CKFinderJava/userfiles/images/image%282672%29.png) +![enter image description here](https://devocean.sk.com/CKFinderJava/userfiles/images/image%282673%29.png) +list의 0, 1번 객체 즉 PyObject를 가리키는 포인터 주소는 메모리 상에서 인접하지만 value는 인접하지 않음 +→ nparray와 비교하면, 캐싱 시 메모리 지역성 문제로 cache hit rate가 더 낮음 diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/12\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/12\354\243\274\354\260\250.md" new file mode 100644 index 0000000..21d7c61 --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/12\354\243\274\354\260\250.md" @@ -0,0 +1,206 @@ +# unittest를 이용해 나만의 Test Case 만들기 +디렉토리 구조는 아래와 같이 구성했습니다. +image +

+ +각 코드는 아래와 같습니다.

+ +### game.py +```python +from abc import ABC, abstractmethod + + +class Unit(ABC): + def __init__(self, _type, _name, _price): + self.type = _type + self.name = _name + self.price = _price + + @abstractmethod + def action(self): + pass + + @abstractmethod + def print(self): + pass + + def get_type(self): + return self.type + + def get_name(self): + return self.name + + def get_price(self): + return self.price + + +class Attacker(Unit): + def __init__(self, type, name, price, _type, _name, _price, _attack_point): + super().__init__(type, name, price) + self.at_ty = _type + self.at_name = _name + self.at_price = _price + self.attack_point = _attack_point + + def action(self): + return self.attack_point + + def print(self): + print(f"[Attacker] Name: {self.at_name} (Attack point: {self.attack_point}, Price: {self.at_price})") + + +class Miner(Unit): + def __init__(self, type, name, price, _type, _name, _price, _mining_point): + super().__init__(type, name, price) + self.mi_ty = _type + self.mi_name = _name + self.mi_price = _price + self.mining_point = _mining_point + + def action(self): + return self.mining_point + + def print(self): + print(f"[Miner] Name: {self.mi_name} (Mining point: {self.mining_point}, Price: {self.mi_price})") + + +class ApplicationType: + def __init__(self): + self.unit_list_in_barracks = [] + self.unit_list = [] + self.curr_turn = 1 + self.MAX_turn = 50 + self.gold = 1000 + self.enemy_hp = 500 + self.flag_status = 0 + + def __del__(self): + for elem in self.unit_list_in_barracks: + del elem + for elem in self.unit_list: + del elem + + def increase_turn(self): + self.curr_turn += 1 + if self.curr_turn == self.MAX_turn: + self.flag_status = 1 + print("You lose") + + def print_unit_list_in_barracks(self): + for elem in self.unit_list_in_barracks: + elem.print() + + def print_unit_list(self): + for elem in self.unit_list: + elem.print() + + def run(self): + while self.flag_status == 0: + sOption = self.get_command() + if sOption == "1": + self.hire_unit() + elif sOption == "2": + self.attack_to_enemy() + elif sOption == "3": + self.gather_money() + elif sOption == "4": + self.print_unit_list() + elif sOption == "5": + break + print("Exit the program...") + + def get_command(self): + print(f"Turn: {self.curr_turn}") + print(f"Gold: {self.gold}") + print(f"Enemy HP: {self.enemy_hp}\n") + print("1. Hire Unit\n2. Attack to Enemy\n3. Gather Money\n4. Print Units\nInput>", end='') + cmd = input() + return cmd + + def hire_unit(self): + pass + + def attack_to_enemy(self): + pass + + def gather_money(self): + pass + +``` +

+ +### test.py +```python +import unittest +from unittest.mock import patch +from io import StringIO + +from game import Attacker, Miner, ApplicationType + + +class TestAttacker(unittest.TestCase): + def test_attacker_action(self): + attacker = Attacker(1, "Attacker1", 100, 1, "Attacker1", 100, 50) + self.assertEqual(attacker.action(), 50) + + def test_attacker_print(self): + attacker = Attacker(1, "Attacker1", 100, 1, "Attacker1", 100, 50) + with patch('sys.stdout', new=StringIO()) as fake_out: + attacker.print() + self.assertEqual(fake_out.getvalue().strip(), "[Attacker] Name: Attacker1 (Attack point: 50, Price: 100)") + + +class TestMiner(unittest.TestCase): + def test_miner_action(self): + miner = Miner(1, "Miner1", 100, 1, "Miner1", 100, 30) + self.assertEqual(miner.action(), 30) + + def test_miner_print(self): + miner = Miner(1, "Miner1", 100, 1, "Miner1", 100, 30) + with patch('sys.stdout', new=StringIO()) as fake_out: + miner.print() + self.assertEqual(fake_out.getvalue().strip(), "[Miner] Name: Miner1 (Mining point: 30, Price: 100)") + + +class TestApplicationType(unittest.TestCase): + def setUp(self): + self.app = ApplicationType() + + def test_initial_values(self): + self.assertEqual(self.app.curr_turn, 1) + self.assertEqual(self.app.MAX_turn, 50) + self.assertEqual(self.app.gold, 1000) + self.assertEqual(self.app.enemy_hp, 500) + self.assertEqual(self.app.flag_status, 0) + + @patch('builtins.input', side_effect=['5']) + def test_run(self): + with patch('sys.stdout', new=StringIO()) as fake_out: + self.app.run() + self.assertIn("Exit the program...", fake_out.getvalue()) + + def test_increase_turn(self): + self.app.increase_turn() + self.assertEqual(self.app.curr_turn, 2) + self.app.curr_turn = 49 + self.app.increase_turn() + self.assertEqual(self.app.flag_status, 1) + + @patch('sys.stdout', new_callable=StringIO) + def test_print_unit_list_in_barracks(self, mock_stdout): + miner = Miner(1, "Miner1", 100, 1, "Miner1", 100, 30) + self.app.unit_list_in_barracks.append(miner) + self.app.print_unit_list_in_barracks() + self.assertIn("[Miner] Name: Miner1 (Mining point: 30, Price: 100)", mock_stdout.getvalue().strip()) + + @patch('sys.stdout', new_callable=StringIO) + def test_print_unit_list(self, mock_stdout): + attacker = Attacker(1, "Attacker1", 100, 1, "Attacker1", 100, 50) + self.app.unit_list.append(attacker) + self.app.print_unit_list() + self.assertIn("[Attacker] Name: Attacker1 (Attack point: 50, Price: 100)", mock_stdout.getvalue().strip()) +``` +

+ +실행 결과는 아래와 같습니다. +image \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/13\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/13\354\243\274\354\260\250.md" new file mode 100644 index 0000000..e2d8852 --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/13\354\243\274\354\260\250.md" @@ -0,0 +1,8 @@ +# pdb 실행 해보기 +image +

+ +# CProfile 예제 파일 직접 생성해서 실행해보기 +12주차 미션으로 제출한 python game.py 코드를 그대로 사용했습니다. 실행 결과는 아래와 같습니다.
+image +image \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/1\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/1\354\243\274\354\260\250.md" new file mode 100644 index 0000000..301175b --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/1\354\243\274\354\260\250.md" @@ -0,0 +1,17 @@ +## CPython 소스코드 다운로드 및 환경 구성 (화면 캡쳐) +![alt text](image.png) +

+ +### 특이 사항 +스터디 노션 환경 구성에 나온 정보대로
+git clone --branch 3.9 https://github.com/python/cpython +
+명령어만 사용하면 사이즈가 커서 RPC fail 에러 발생.
+그래서 뒤에 "--depth 1" 을 추가로 붙여 얕은 클론만 해둔 상태.
+필요한 경우 "git fetch --unshallow"로 다른 레포들도 갖고 와야 한다.
+*참고: https://eunjinii.tistory.com/128 +

+ + +## 스터디에서 이루고 싶은 목표, 함께 하게 된 소감 등 +그동안 파이썬을 사용하면서 궁금했던 점들을 알아 가며 호기심을 해소할 수 있는 기회가 됐음 합니다! \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/2\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/2\354\243\274\354\260\250.md" new file mode 100644 index 0000000..59421c0 --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/2\354\243\274\354\260\250.md" @@ -0,0 +1,8 @@ +# 2주차 + +## 컴파일 완료된 화면 캡쳐 (./python.exe 실행 화면) +image + + +## 문법 다시 생성하기 (pass 키워드 변경해보기) 부분 원하는 키워드 다른걸로 바꿔보기 +image \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/3\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/3\354\243\274\354\260\250.md" new file mode 100644 index 0000000..91877f1 --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/3\354\243\274\354\260\250.md" @@ -0,0 +1,5 @@ +## 파이썬 세션에서 runtime flag 확인하기 +image + +## importlib.util.find_spec 함수를 사용해서 원하는 모듈의 위치를 찾아보기 +image \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/4\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/4\354\243\274\354\260\250.md" new file mode 100644 index 0000000..0005a0b --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/4\354\243\274\354\260\250.md" @@ -0,0 +1,6 @@ +# 1. instaviz로 AST 시각화 +image +

+ +# 2. ‘거의 같음’ 연산자를 문법에 추가하고 AlE타입의 객체를 출력 +image \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/5\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/5\354\243\274\354\260\250.md" new file mode 100644 index 0000000..04bdee8 --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/5\354\243\274\354\260\250.md" @@ -0,0 +1,2 @@ +# ‘거의 같음’ 연산자 구현하기 +image \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/6\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/6\354\243\274\354\260\250.md" new file mode 100644 index 0000000..674475c --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/6\354\243\274\354\260\250.md" @@ -0,0 +1,45 @@ +## 1. 사용한 코드 +```python +import inspect + +def minBitFlips3(start: int, goal: int) -> int: + flips, xor = 0, start ^ goal + while xor != 0: + flips += 1 + xor &= (xor - 1) + print_frame_info() + return flips + + + +def minBitFlips4(start: int, goal: int) -> int: + x = start ^ goal + count = 0 + while x: + x = x & (x - 1) + count += 1 + print_frame_info() + return count + + +def print_frame_info(): + frame = inspect.currentframe().f_back # 현재 함수의 호출자 프레임 + try: + print("Function Name:", frame.f_code.co_name) + print("File Name:", frame.f_code.co_filename) + print("Line No:", frame.f_back.f_lineno) + print("Local Variables:", list(frame.f_locals.keys())) + print("Global Variables:", list(frame.f_globals.keys())) + # dis.dis(frame.f_code) # 역 디스어셈블러 + print("\\n\\n") + finally: + del frame + + +minBitFlips3(1, 10) +minBitFlips4(1, 10) +``` +
+ +## 2. 실행 결과 +image \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/7\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/7\354\243\274\354\260\250.md" new file mode 100644 index 0000000..a542b1b --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/7\354\243\274\354\260\250.md" @@ -0,0 +1,9 @@ +- tracemalloc 통해 직접 메모리 확인해보기 + +아래 레포지토리의 코드(프로그램)를 통해 메모리를 확인해보았습니다.
+https://github.com/secureWKkim/web-crawling-on-container +

+ +실행 결과는 아래와 같습니다.
+스크린샷 2024-06-03 오후 3 05 44 +스크린샷 2024-06-03 오후 3 05 53 \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/8\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/8\354\243\274\354\260\250.md" new file mode 100644 index 0000000..291631e --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/8\354\243\274\354\260\250.md" @@ -0,0 +1,2 @@ +### 원하는 라이브러리 import 해보고, 참조 카운트가 어떻게 바뀌는지 출력해보기 +스크린샷 2024-06-03 오후 5 31 27 \ No newline at end of file diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/9\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\233\220\352\262\275/9\354\243\274\354\260\250.md" new file mode 100644 index 0000000..0dac85b --- /dev/null +++ "b/8th_members/\352\271\200\354\233\220\352\262\275/9\354\243\274\354\260\250.md" @@ -0,0 +1,5 @@ +### 10.3.8 애플리케이션 예제 두 코드 실행해보기 +1개 이상의 port가 출력되도록 만들기 위해 검사하는 port 번호 range를 0~99로 변경했습니다.
+ +스크린샷 2024-06-03 오후 6 50 35 +스크린샷 2024-06-03 오후 6 33 17 diff --git "a/8th_members/\352\271\200\354\233\220\352\262\275/image.png" "b/8th_members/\352\271\200\354\233\220\352\262\275/image.png" new file mode 100644 index 0000000..94002c9 Binary files /dev/null and "b/8th_members/\352\271\200\354\233\220\352\262\275/image.png" differ diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/10\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/10\354\243\274\354\260\250.md" new file mode 100644 index 0000000..00648e1 --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/10\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 10주차 + +## Port Scanner: Multi Threading +스크린샷 2024-06-09 오후 11 15 02 diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/11\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/11\354\243\274\354\260\250.md" new file mode 100644 index 0000000..636ced4 --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/11\354\243\274\354\260\250.md" @@ -0,0 +1,391 @@ +# 11주차 + +## 원하는 type 정해서 구조체 및 type 코드 분석해보기 + +### String type + +```c +// Include/unicodeobject.h + +PyAPI_DATA(PyTypeObject) PyUnicode_Type; +PyAPI_DATA(PyTypeObject) PyUnicodeIter_Type; +``` +- `PyUnicode_Type` : 기본 문자열 타입, Python 문자열 객체의 모든 메타데이터와 메서드를 포함 +- `PyUnicodeIter_Type` : 문자열 이터레이터 타입, 문자열을 순회할 때 사용 + +### `PyUnicode_Type` + +```c +// Objects/unicodeobject.c + +PyTypeObject PyUnicode_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "str", /* tp_name */ + sizeof(PyUnicodeObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* Slots */ + (destructor)unicode_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + unicode_repr, /* tp_repr */ + &unicode_as_number, /* tp_as_number */ + &unicode_as_sequence, /* tp_as_sequence */ + &unicode_as_mapping, /* tp_as_mapping */ + (hashfunc) unicode_hash, /* tp_hash*/ + 0, /* tp_call*/ + (reprfunc) unicode_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_UNICODE_SUBCLASS, /* tp_flags */ + unicode_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + PyUnicode_RichCompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + unicode_iter, /* tp_iter */ + 0, /* tp_iternext */ + unicode_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyBaseObject_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + unicode_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; +``` + +### `PyUnicodeIter_Type` + +```c +// Objects/unicodeobject.c + +PyTypeObject PyUnicodeIter_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "str_iterator", /* tp_name */ + sizeof(unicodeiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)unicodeiter_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC,/* tp_flags */ + 0, /* tp_doc */ + (traverseproc)unicodeiter_traverse, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)unicodeiter_next, /* tp_iternext */ + unicodeiter_methods, /* tp_methods */ + 0, +}; +``` + +### `unicode_new` + +```c +// Objects/unicodeobject.c + +static PyObject * +unicode_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject *x = NULL; + static char *kwlist[] = {"object", "encoding", "errors", 0}; + char *encoding = NULL; + char *errors = NULL; + + if (type != &PyUnicode_Type) + return unicode_subtype_new(type, args, kwds); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Oss:str", + kwlist, &x, &encoding, &errors)) + return NULL; + if (x == NULL) + _Py_RETURN_UNICODE_EMPTY(); + if (encoding == NULL && errors == NULL) + return PyObject_Str(x); + else + return PyUnicode_FromEncodedObject(x, encoding, errors); +} +``` + +1. 타입 확인 +2. `PyArg_ParseTupleAndKeywords`를 통해 인자 파싱 +3. 객체 생성 + +### `PyUnicode_New` + +```c +// Objects/unicodeobject.c + +PyObject * +PyUnicode_New(Py_ssize_t size, Py_UCS4 maxchar) +{ + PyObject *obj; + PyCompactUnicodeObject *unicode; + void *data; + enum PyUnicode_Kind kind; + int is_sharing, is_ascii; + Py_ssize_t char_size; + Py_ssize_t struct_size; + + /* Optimization for empty strings */ + if (size == 0 && unicode_empty != NULL) { + Py_INCREF(unicode_empty); + return unicode_empty; + } + + is_ascii = 0; + is_sharing = 0; + struct_size = sizeof(PyCompactUnicodeObject); + if (maxchar < 128) { + kind = PyUnicode_1BYTE_KIND; + char_size = 1; + is_ascii = 1; + struct_size = sizeof(PyASCIIObject); + } + else if (maxchar < 256) { + kind = PyUnicode_1BYTE_KIND; + char_size = 1; + } + else if (maxchar < 65536) { + kind = PyUnicode_2BYTE_KIND; + char_size = 2; + if (sizeof(wchar_t) == 2) + is_sharing = 1; + } + else { + if (maxchar > MAX_UNICODE) { + PyErr_SetString(PyExc_SystemError, + "invalid maximum character passed to PyUnicode_New"); + return NULL; + } + kind = PyUnicode_4BYTE_KIND; + char_size = 4; + if (sizeof(wchar_t) == 4) + is_sharing = 1; + } + + /* Ensure we won't overflow the size. */ + if (size < 0) { + PyErr_SetString(PyExc_SystemError, + "Negative size passed to PyUnicode_New"); + return NULL; + } + if (size > ((PY_SSIZE_T_MAX - struct_size) / char_size - 1)) + return PyErr_NoMemory(); + + /* Duplicated allocation code from _PyObject_New() instead of a call to + * PyObject_New() so we are able to allocate space for the object and + * it's data buffer. + */ + obj = (PyObject *) PyObject_MALLOC(struct_size + (size + 1) * char_size); + if (obj == NULL) + return PyErr_NoMemory(); + obj = PyObject_INIT(obj, &PyUnicode_Type); + if (obj == NULL) + return NULL; + + unicode = (PyCompactUnicodeObject *)obj; + if (is_ascii) + data = ((PyASCIIObject*)obj) + 1; + else + data = unicode + 1; + _PyUnicode_LENGTH(unicode) = size; + _PyUnicode_HASH(unicode) = -1; + _PyUnicode_STATE(unicode).interned = 0; + _PyUnicode_STATE(unicode).kind = kind; + _PyUnicode_STATE(unicode).compact = 1; + _PyUnicode_STATE(unicode).ready = 1; + _PyUnicode_STATE(unicode).ascii = is_ascii; + if (is_ascii) { + ((char*)data)[size] = 0; + _PyUnicode_WSTR(unicode) = NULL; + } + else if (kind == PyUnicode_1BYTE_KIND) { + ((char*)data)[size] = 0; + _PyUnicode_WSTR(unicode) = NULL; + _PyUnicode_WSTR_LENGTH(unicode) = 0; + unicode->utf8 = NULL; + unicode->utf8_length = 0; + } + else { + unicode->utf8 = NULL; + unicode->utf8_length = 0; + if (kind == PyUnicode_2BYTE_KIND) + ((Py_UCS2*)data)[size] = 0; + else /* kind == PyUnicode_4BYTE_KIND */ + ((Py_UCS4*)data)[size] = 0; + if (is_sharing) { + _PyUnicode_WSTR_LENGTH(unicode) = size; + _PyUnicode_WSTR(unicode) = (wchar_t *)data; + } + else { + _PyUnicode_WSTR_LENGTH(unicode) = 0; + _PyUnicode_WSTR(unicode) = NULL; + } + } +#ifdef Py_DEBUG + unicode_fill_invalid((PyObject*)unicode, 0); +#endif + assert(_PyUnicode_CheckConsistency((PyObject*)unicode, 0)); + return obj; +} +``` + +1. empty string 처리 +2. 유니코드 종류 결정 +3. 메모리 할당 +4. `PyObject_INIT`을 통해 객체 초기화 +5. 객체 상태 초기화 +6. 데이터 초기화 +7. 디버깅 모드일 경우 `unicode_fill_invalid`를 통해 객체 검사 + +### `_PyUnicode_New` + +```c +// Objects/unicodeobject.c + +static PyUnicodeObject * +_PyUnicode_New(Py_ssize_t length) +{ + PyUnicodeObject *unicode; + size_t new_size; + + /* Optimization for empty strings */ + if (length == 0 && unicode_empty != NULL) { + Py_INCREF(unicode_empty); + return (PyUnicodeObject*)unicode_empty; + } + + /* Ensure we won't overflow the size. */ + if (length > ((PY_SSIZE_T_MAX / (Py_ssize_t)sizeof(Py_UNICODE)) - 1)) { + return (PyUnicodeObject *)PyErr_NoMemory(); + } + if (length < 0) { + PyErr_SetString(PyExc_SystemError, + "Negative size passed to _PyUnicode_New"); + return NULL; + } + + unicode = PyObject_New(PyUnicodeObject, &PyUnicode_Type); + if (unicode == NULL) + return NULL; + new_size = sizeof(Py_UNICODE) * ((size_t)length + 1); + + _PyUnicode_WSTR_LENGTH(unicode) = length; + _PyUnicode_HASH(unicode) = -1; + _PyUnicode_STATE(unicode).interned = 0; + _PyUnicode_STATE(unicode).kind = 0; + _PyUnicode_STATE(unicode).compact = 0; + _PyUnicode_STATE(unicode).ready = 0; + _PyUnicode_STATE(unicode).ascii = 0; + _PyUnicode_DATA_ANY(unicode) = NULL; + _PyUnicode_LENGTH(unicode) = 0; + _PyUnicode_UTF8(unicode) = NULL; + _PyUnicode_UTF8_LENGTH(unicode) = 0; + + _PyUnicode_WSTR(unicode) = (Py_UNICODE*) PyObject_MALLOC(new_size); + if (!_PyUnicode_WSTR(unicode)) { + Py_DECREF(unicode); + PyErr_NoMemory(); + return NULL; + } + + /* Initialize the first element to guard against cases where + * the caller fails before initializing str -- unicode_resize() + * reads str[0], and the Keep-Alive optimization can keep memory + * allocated for str alive across a call to unicode_dealloc(unicode). + * We don't want unicode_resize to read uninitialized memory in + * that case. + */ + _PyUnicode_WSTR(unicode)[0] = 0; + _PyUnicode_WSTR(unicode)[length] = 0; + + assert(_PyUnicode_CheckConsistency((PyObject *)unicode, 0)); + return unicode; +} +``` + +1. empty string 처리 +2. size 유효성 체크 +3. `PyObject_New`를 통해 객체 생성 +4. 메모리 할당 및 초기화 +5. 아래 코드를 통해 메모리 초기화 + ```c + _PyUnicode_WSTR(unicode)[0] = 0; + _PyUnicode_WSTR(unicode)[length] = 0; + ``` +6. `_PyUnicode_CheckConsistency`를 통해 객체 검증 + +### `unicode_fill` + +문자열 데이터를 특정 값으로 채우는 기능 수행, 메모리 초기화 및 데이터 채우기 작업에 사용 + +```c +// Objects/unicodeobject.c + +static inline void +unicode_fill(enum PyUnicode_Kind kind, void *data, Py_UCS4 value, + Py_ssize_t start, Py_ssize_t length) +{ + assert(0 <= start); + assert(kind != PyUnicode_WCHAR_KIND); + switch (kind) { + case PyUnicode_1BYTE_KIND: { + assert(value <= 0xff); + Py_UCS1 ch = (unsigned char)value; + Py_UCS1 *to = (Py_UCS1 *)data + start; + memset(to, ch, length); + break; + } + case PyUnicode_2BYTE_KIND: { + assert(value <= 0xffff); + Py_UCS2 ch = (Py_UCS2)value; + Py_UCS2 *to = (Py_UCS2 *)data + start; + const Py_UCS2 *end = to + length; + for (; to < end; ++to) *to = ch; + break; + } + case PyUnicode_4BYTE_KIND: { + assert(value <= MAX_UNICODE); + Py_UCS4 ch = value; + Py_UCS4 * to = (Py_UCS4 *)data + start; + const Py_UCS4 *end = to + length; + for (; to < end; ++to) *to = ch; + break; + } + default: Py_UNREACHABLE(); + } +} +``` + +- Parameters + - `enum PyUnicode_Kind kind` : 문자열 유니코드 인코딩 종류 + - `void *data` : 문자열 데이터 + - `Py_UCS4 value` : 채울 유니코드 값 + - `Py_ssize_t start` : 문자열 데이터를 채우기 시작할 위치 + - `Py_ssize_t length` : 채울 길이 + +1. 시작 위치 유효성 체크 +2. 유니코드 종류에 따른 방식으로 데이터 채우기 diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/12\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/12\354\243\274\354\260\250.md" new file mode 100644 index 0000000..ef995c8 --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/12\354\243\274\354\260\250.md" @@ -0,0 +1,77 @@ +# 12주차 + +## 나만의 Test Case 만들기 + +### 구조 + +``` +. +├── tests +│ └── test_normalize.py +└── text_processing.py +``` + +### `text_processing.py` + +```python +def normalize(input_str): + out = input_str.lower() + out = out.strip() + while ' ' in out: + out = out.replace(' ', ' ') + return out +``` + +### `test_normalize.py` + +```python +import unittest +from text_processing import normalize + + +class TestTextNormalize(unittest.TestCase): + def test_normalize(self): + test_str = "This is an example." + pred = normalize(test_str) + self.assertEqual(pred, "this is an example.") + + test_str = " EXTRA SPACE " + pred = normalize(test_str) + self.assertEqual(pred, "extra space") + + test_str = "THIS IS ALL CAPS!!" + pred = normalize(test_str) + self.assertEqual(pred, "this is all caps!!") + + test_str = " " + pred = normalize(test_str) + self.assertEqual(pred, "") + + test_str = "this is all lower space..." + pred = normalize(test_str) + self.assertEqual(pred, "this is all lower space...") + + test_str = " H e L l O !" + pred = normalize(test_str) + self.assertEqual(pred, "h e l l o !") + + test_str = "" + pred = normalize(test_str) + self.assertEqual(pred, "") + + test_str = "........" + pred = normalize(test_str) + self.assertEqual(pred, "........") + + test_str = "EX A M P LE" + pred = normalize(test_str) + self.assertEqual(pred, "ex a m p le") + + test_str = "AbCd EfGh IjKl MnOp" + pred = normalize(test_str) + self.assertEqual(pred, "abcd efgh ijkl mnop") +``` + +### 결과 + +스크린샷 2024-06-30 오후 12 29 06 diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/13\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/13\354\243\274\354\260\250.md" new file mode 100644 index 0000000..220c5b8 --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/13\354\243\274\354\260\250.md" @@ -0,0 +1,43 @@ +# 13주차 + +## pbd 실행해보기 + +```python +def calculate_performance_improvement_rate(before, after): + return (before - after) / after * 100 + + +if __name__ == "__main__": + breakpoint() + + before_performance = 150 + after_performance = 57 + + performance_improvement_rate = calculate_performance_improvement_rate(before_performance, after_performance) + + print(f"{performance_improvement_rate:.2f}%") + +``` + +스크린샷 2024-06-30 오후 3 02 32 + + +## CProfile 예제 파일 직접 생성해서 실행해보기 + +```python +def calculate_performance_improvement_rate(before, after): + return (before - after) / after * 100 + + +if __name__ == "__main__": + before_performance = 150 + after_performance = 57 + + performance_improvement_rate = calculate_performance_improvement_rate(before_performance, after_performance) + + print(f"{performance_improvement_rate:.2f}%") +``` + +스크린샷 2024-06-30 오후 3 05 17 + +스크린샷 2024-06-30 오후 3 06 17 diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/1\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/1\354\243\274\354\260\250.md" new file mode 100644 index 0000000..fb156ea --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/1\354\243\274\354\260\250.md" @@ -0,0 +1,9 @@ +# 1주차 + +## CPython 소스코드 다운로드 및 환경 구성 (화면 캡쳐) +스크린샷 2024-03-17 오후 11 11 04 + +## 스터디에서 이루고 싶은 목표, 함께 하게 된 소감 등 +- Python을 깊이 이해하여 Python을 잘 활용하는 개발자가 되고 싶습니다. +- Python의 내부 구조와 코드를 파악하며 Python의 철학을 이해하고 좋은 코드에 대해서도 배워가고 싶습니다. +- 같이 스터디하면서 많이 배우겠습니다! 재밌고 보람찬 시간이 될 수 있도록 열심히 참여하겠습니다. diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/2\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/2\354\243\274\354\260\250.md" new file mode 100644 index 0000000..032d9a5 --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/2\354\243\274\354\260\250.md" @@ -0,0 +1,7 @@ +# 2주차 + +## 컴파일 완료된 화면 캡쳐 (./python.exe 실행 화면) +스크린샷 2024-03-23 오후 11 31 31 + +## 문법 다시 생성하기 (pass 키워드 변경해보기) 부분 원하는 키워드 다른걸로 바꿔보기 (결과 화면 캡쳐) +스크린샷 2024-03-23 오후 11 42 18 diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/3\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/3\354\243\274\354\260\250.md" new file mode 100644 index 0000000..e3c1e49 --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/3\354\243\274\354\260\250.md" @@ -0,0 +1,12 @@ +# 3주차 + +## CPython 인터프리터 실행 과정 코드 레벨로 이해하기 +스크린샷 2024-04-07 오후 6 05 05 + +## 파이썬 세션에서 runtime flag 확인하기 +스크린샷 2024-04-07 오후 6 06 29 + + +## importlib.util.find_spec 함수를 사용해서 원하는 모듈의 위치를 찾아보기 +스크린샷 2024-04-07 오후 6 11 14 + diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/4\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/4\354\243\274\354\260\250.md" new file mode 100644 index 0000000..ca86875 --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/4\354\243\274\354\260\250.md" @@ -0,0 +1,17 @@ +# 4주차 + +## instaviz로 AST 시각화 해보기 +```python +def pow(x, y): + result = 1 + for i in range(0, y): + result *= x + return result + +import instaviz +instaviz.show(pow) +``` +![image](https://github.com/mikaniz/CPython-Guide/assets/92143119/e0462f9b-f336-4813-a585-2cf34f6794bc) + +## ‘거의 같음’ 연산자를 문법에 추가하고 AlE타입의 객체를 출력 해보기 +스크린샷 2024-04-22 오후 9 55 21 diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/5\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/5\354\243\274\354\260\250.md" new file mode 100644 index 0000000..75ed16a --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/5\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 4주차 + +## ‘거의 같음’ 연산자 구현 +스크린샷 2024-04-28 오후 11 21 51 diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/6\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/6\354\243\274\354\260\250.md" new file mode 100644 index 0000000..984d33b --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/6\354\243\274\354\260\250.md" @@ -0,0 +1,35 @@ +# 6주차 + +## 파이썬에서 프레임 객체 접근해보기 +```python +import inspect + + +def print_frame_info(): + frame = inspect.currentframe().f_back + try: + print("Function Name:", frame.f_code.co_name) + print("File Name:", frame.f_code.co_filename) + print("Line No:", frame.f_back.f_lineno) + print("Local Variables:", list(frame.f_locals.keys())) + print("Global Variables:", list(frame.f_globals.keys())) + finally: + del frame + + +def print_sum(n1, n2): + sum = n1 + n2 + print(sum) + print_frame_info() + + +def print_upper(word): + upper_word = word.upper() + print(upper_word) + print_frame_info() + + +print_sum(10, 20) +print_upper("Python") +``` +스크린샷 2024-05-12 오후 8 14 24 diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/7\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/7\354\243\274\354\260\250.md" new file mode 100644 index 0000000..30c2c9b --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/7\354\243\274\354\260\250.md" @@ -0,0 +1,35 @@ +# 7주차 + +## tracemalloc 모듈 사용해서 직접 메모리 확인해보기 +```python +import tracemalloc + + +def fac_with_recursion(n): + if n <= 1: + return n + return n * fac_with_recursion(n - 1) + + +def fac_with_loop(n): + result = 1 + for i in range(1, n): + result *= i + return result + + +tracemalloc.start() + +fac_10_with_recursion = fac_with_recursion(10) +fac_10_with_loop = fac_with_loop(10) + +snapshot = tracemalloc.take_snapshot() +snapshot = snapshot.filter_traces([tracemalloc.Filter(True, "**/tracemalloc_example.py")]) +stats = snapshot.statistics("lineno") + +for stat in stats: + print(stat, stat.traceback.format()) + +tracemalloc.stop() +``` +스크린샷 2024-05-21 오전 12 27 46 diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/8\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/8\354\243\274\354\260\250.md" new file mode 100644 index 0000000..184fff0 --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/8\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 8주차 + +## 원하는 라이브러리 import 해보고, 참조 카운트가 어떻게 바뀌는지 출력해보기 +스크린샷 2024-05-26 오후 11 17 08 diff --git "a/8th_members/\352\271\200\354\247\204\354\225\204/9\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\354\247\204\354\225\204/9\354\243\274\354\260\250.md" new file mode 100644 index 0000000..c9cdb12 --- /dev/null +++ "b/8th_members/\352\271\200\354\247\204\354\225\204/9\354\243\274\354\260\250.md" @@ -0,0 +1,7 @@ +# 9주차 + +## Port Scanner: Queue +스크린샷 2024-06-09 오후 11 10 47 + +## Port Scanner: multiprocessing.Queue +스크린샷 2024-06-09 오후 11 11 38 diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/10\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/10\354\243\274\354\260\250.md" new file mode 100644 index 0000000..b48399e --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/10\354\243\274\354\260\250.md" @@ -0,0 +1,120 @@ +# Port Scanner 예제 실행해보기 + +### 싱글 프로세스 + 싱글 스레드 +```python3 +from queue import Queue +import socket +import time + +timeout = 1.0 + +def check_port(host: str, port: int, results: Queue): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(timeout) + result = sock.connect_ex((host, port)) + if result == 0: + results.put(port) + sock.close() + +def main(): + start = time.time() + host = "localhost" # Replace with a host you own + results = Queue() + for port in range(30000, 65536): + check_port(host, port, results) + while not results.empty(): + print("Port {0} is open".format(results.get())) + print("Completed scan in {0} seconds".format(time.time() - start)) + +if __name__ == '__main__': + main() +``` +Screenshot 2024-06-30 at 2 44 52 PM + + +### 멀티스레딩 + + +```python3 +from threading import Thread +from queue import Queue +import socket +import time + +timeout = 1.0 + +def check_port(host: str, port: int, results: Queue): + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.settimeout(timeout) + result = sock.connect_ex((host, port)) + if result == 0: + results.put(port) + sock.close() + +def main(): + start = time.time() + host = "localhost" # Replace with a host you own + threads = [] + results = Queue() + for port in range(30000, 65536): + t = Thread(target=check_port, args=(host, port, results)) + t.start() + threads.append(t) + for t in threads: + t.join() + while not results.empty(): + print("Port {0} is open".format(results.get())) + print("Completed scan in {0} seconds".format(time.time() - start)) + +if __name__ == '__main__': + main() +``` +Screenshot 2024-06-30 at 2 45 36 PM + + +### 멀티스레딩 + 스레드 개수 제한 +```python3 +import socket +import time +from concurrent.futures import ThreadPoolExecutor, as_completed +from queue import Queue + +timeout = 1.0 + + +def check_port(host: str, port: int) -> int: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.settimeout(timeout) + result = sock.connect_ex((host, port)) + if result == 0: + return port + return None + + +def main(): + start = time.time() + host = "localhost" # Replace with a host you own + open_ports = [] + + with ThreadPoolExecutor(max_workers=50) as executor: + futures = [executor.submit(check_port, host, port) + for port in range(30000, 65536)] + + for future in as_completed(futures): + port = future.result() + if port is not None: + open_ports.append(port) + + for port in open_ports: + print(f"Port {port} is open") + print(f"Completed scan in {time.time() - start:.2f} seconds") + + +if __name__ == '__main__': + main() + +``` + +Screenshot 2024-06-30 at 2 46 34 PM + + diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/11\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/11\354\243\274\354\260\250.md" new file mode 100644 index 0000000..213ffc9 --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/11\354\243\274\354\260\250.md" @@ -0,0 +1,102 @@ + +# dictionay 타입에 대해서 알아보자 +### dict get + +```c +static inline Py_ssize_t +dictkeys_get_index(const PyDictKeysObject *keys, Py_ssize_t i) +{ + Py_ssize_t s = DK_SIZE(keys); + Py_ssize_t ix; + + if (s <= 0xff) { + const int8_t *indices = (const int8_t*)(keys->dk_indices); + ix = indices[i]; + } + else if (s <= 0xffff) { + const int16_t *indices = (const int16_t*)(keys->dk_indices); + ix = indices[i]; + } +#if SIZEOF_VOID_P > 4 + else if (s > 0xffffffff) { + const int64_t *indices = (const int64_t*)(keys->dk_indices); + ix = indices[i]; + } +#endif + else { + const int32_t *indices = (const int32_t*)(keys->dk_indices); + ix = indices[i]; + } + assert(ix >= DKIX_DUMMY); + return ix; +} +``` + +### dict set +```c +static inline void +dictkeys_set_index(PyDictKeysObject *keys, Py_ssize_t i, Py_ssize_t ix) +{ + Py_ssize_t s = DK_SIZE(keys); + + assert(ix >= DKIX_DUMMY); + + if (s <= 0xff) { + int8_t *indices = (int8_t*)(keys->dk_indices); + assert(ix <= 0x7f); + indices[i] = (char)ix; + } + else if (s <= 0xffff) { + int16_t *indices = (int16_t*)(keys->dk_indices); + assert(ix <= 0x7fff); + indices[i] = (int16_t)ix; + } +#if SIZEOF_VOID_P > 4 + else if (s > 0xffffffff) { + int64_t *indices = (int64_t*)(keys->dk_indices); + indices[i] = ix; + } +#endif + else { + int32_t *indices = (int32_t*)(keys->dk_indices); + assert(ix <= 0x7fffffff); + indices[i] = (int32_t)ix; + } +} +``` + +### dict new +```c +static PyObject * +new_dict(PyDictKeysObject *keys, PyObject **values) +{ + PyDictObject *mp; + assert(keys != NULL); +#if PyDict_MAXFREELIST > 0 + if (numfree) { + mp = free_list[--numfree]; + assert (mp != NULL); + assert (Py_IS_TYPE(mp, &PyDict_Type)); + _Py_NewReference((PyObject *)mp); + } + else +#endif + { + mp = PyObject_GC_New(PyDictObject, &PyDict_Type); + if (mp == NULL) { + dictkeys_decref(keys); + if (values != empty_values) { + free_values(values); + } + return NULL; + } + } + mp->ma_keys = keys; + mp->ma_values = values; + mp->ma_used = 0; + mp->ma_version_tag = DICT_NEXT_VERSION(); + ASSERT_CONSISTENT(mp); + return (PyObject *)mp; +} +``` + diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/12\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/12\354\243\274\354\260\250.md" new file mode 100644 index 0000000..673839b --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/12\354\243\274\354\260\250.md" @@ -0,0 +1,53 @@ + +# 나만의 Test Case 만들기 + +```python3 +def is_prime(n): + """ + Check if a number is a prime number. + + Parameters: + n (int): The number to check. + + Returns: + bool: True if n is a prime number, False otherwise. + """ + if n <= 1: + return False + if n <= 3: + return True + if n % 2 == 0 or n % 3 == 0: + return False + i = 5 + while i * i <= n: + if n % i == 0 or n % (i + 2) == 0: + return False + i += 6 + return True + + +# Example usage: +if __name__ == "__main__": + print(is_prime(29)) # Expected output: True + print(is_prime(15)) # Expected output: False +``` + + +``` +import unittest + +from src import example + + +class TestIsPrime(unittest.TestCase): + def test_is_prime(self): + self.assertEqual(example.is_prime(2), True) + self.assertEqual(example.is_prime(3), True) + self.assertEqual(example.is_prime(4), False) + self.assertEqual(example.is_prime(5), True) + self.assertEqual(example.is_prime(7), True) + +``` +Screenshot 2024-06-30 at 5 16 31 PM + + diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/13\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/13\354\243\274\354\260\250.md" new file mode 100644 index 0000000..fb327aa --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/13\354\243\274\354\260\250.md" @@ -0,0 +1,43 @@ +# pdb 실행 해보기 + +Screenshot 2024-06-30 at 5 23 18 PM + + + +# CProfile 예제 직접 실행해보기 + +```python3 +# example.py + +import cProfile +import pstats +import io + +def slow_function(): + total = 0 + for i in range(10000): + for j in range(10000): + total += i * j + return total + +def fast_function(): + return sum(i * j for i in range(1000) for j in range(1000)) + +def main(): + slow_function() + fast_function() + +if __name__ == '__main__': + pr = cProfile.Profile() + pr.enable() + main() + pr.disable() + + s = io.StringIO() + sortby = 'cumulative' + ps = pstats.Stats(pr, stream=s).sort_stats(sortby) + ps.print_stats() + print(s.getvalue()) + +``` +Screenshot 2024-06-30 at 5 31 22 PM diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/1\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/1\354\243\274\354\260\250.md" new file mode 100644 index 0000000..b2fec39 --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/1\354\243\274\354\260\250.md" @@ -0,0 +1,11 @@ +# 1주차 + +## CPython 소스코드 다운로드 및 환경 구성 + +Screenshot 2024-03-11 at 11 56 05 PM + +## 스터디에서 이루고 싶은 목표, 함께 하게 된 소감 + +- 한국어로 된 문서 중 가장 좋은 Cpython 문서 만들기!! +- 이제 백준 문제 풀이 시간 순위 1등은 내꺼! +- 어디가서 파이썬 좀 안다 자신있게 말하기 diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/2\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/2\354\243\274\354\260\250.md" new file mode 100644 index 0000000..a66732a --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/2\354\243\274\354\260\250.md" @@ -0,0 +1,11 @@ +## 문법 다시 생성하기 (pass 키워드 변경해보기) 부분 원하는 키워드 다른걸로 바꿔보기 (결과 화면 캡쳐) +### 1. pass -> do_nothing +Screenshot 2024-03-19 at 5 43 11 AM + +### 2. break -> stop +Screenshot 2024-03-19 at 6 17 41 AM + +### lzma.h 을 찾을 수 없다는 에러 +Screenshot 2024-03-19 at 6 19 27 AM + +- 맥 기준 brew install xz 하면 해결된다는데 저는 안되네요.. ㅠㅠ diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/3\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/3\354\243\274\354\260\250.md" new file mode 100644 index 0000000..2b55ba0 --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/3\354\243\274\354\260\250.md" @@ -0,0 +1,8 @@ +# 3주차 + +## 파이썬 세션에서 runtime flag 확인하기 +Screenshot 2024-04-13 at 11 51 33 PM + + +## importlib.util.find_spec 함수를 사용해서 원하는 모듈의 위치를 찾아보기 +Screenshot 2024-04-13 at 11 55 33 PM diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/4\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/4\354\243\274\354\260\250.md" new file mode 100644 index 0000000..3ebde9c --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/4\354\243\274\354\260\250.md" @@ -0,0 +1,25 @@ +- instaviz로 AST 시각화 해보기 + +```python3 +def scramble_word(word): + word_list = list(word) + random.shuffle(word_list) + return ''.join(word_list) +``` + +Screenshot 2024-04-16 at 2 38 25 PM +Screenshot 2024-04-16 at 2 39 00 PM +Screenshot 2024-04-16 at 2 39 28 PM +Screenshot 2024-04-16 at 2 39 38 PM + + +- ‘거의 같음’ 연산자를 문법에 추가하고 ALE 타입의 객체를 출력 해보기 + +Screenshot 2024-04-16 at 2 41 26 PM + +```shell +make regen-token regen-pegen +make regen-ast +make -j2 -s +``` + diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/5\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/5\354\243\274\354\260\250.md" new file mode 100644 index 0000000..2202150 --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/5\354\243\274\354\260\250.md" @@ -0,0 +1,3 @@ +# 거의 같음 연산자 구현 + +Screenshot 2024-04-28 at 10 18 27 PM diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/6\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/6\354\243\274\354\260\250.md" new file mode 100644 index 0000000..caeade8 --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/6\354\243\274\354\260\250.md" @@ -0,0 +1,47 @@ +```python3 +import inspect +import re + + +def print_frame_info(): + frame = inspect.currentframe().f_back # 현재 함수의 호출자 프레임 + try: + print("Function Name:", frame.f_code.co_name) + print("File Name:", frame.f_code.co_filename) + print("Line No:", frame.f_back.f_lineno) + print("Local Variables:", list(frame.f_locals.keys())) + print("Global Variables:", list(frame.f_globals.keys())) + # dis.dis(frame.f_code) # 역 디스어셈블러 + print("\\n\\n") + finally: + del frame + + +def validate_email(email): + pattern = r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$" + if re.match(pattern, email): + print_frame_info() + + return True + else: + print_frame_info() + + return False + + +def check_password_complexity(password): + if (len(password) >= 8 and + any(c.isupper() for c in password) and + any(c.islower() for c in password) and + any(c.isdigit() for c in password) and + any(c in '!@#$%^&*()-_=+[]{}|;:",.<>?`~' for c in password)): + print_frame_info() + return True + else: + print_frame_info() + return False + +validate_email("pilmokim99@gmail.com") +check_password_complexity("1234") +``` +Screenshot 2024-05-13 at 8 36 10 PM diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/7\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/7\354\243\274\354\260\250.md" new file mode 100644 index 0000000..cfcf62b --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/7\354\243\274\354\260\250.md" @@ -0,0 +1,50 @@ + +## 코드 +```python +import tracemalloc +import linecache +import random +import numpy as np + +def memory_intensive_function(size): + data = [random.randint(1, 1000000) for _ in range(size)] + sorted_data = sorted(data) + mid_index = len(sorted_data) // 2 + return sorted_data[mid_index] + + +def matrix_multiply(size): + # size x size 크기의 무작위 행렬 두 개 생성 + matrix1 = np.random.rand(size, size) + matrix2 = np.random.rand(size, size) + # 두 행렬의 곱 계산 + product = np.dot(matrix1, matrix2) + return product + + +def main(): + tracemalloc.start() + x = memory_intensive_function(100000) + y = matrix_multiply(100) + snapshot = tracemalloc.take_snapshot() + snapshot = snapshot.filter_traces(( + tracemalloc.Filter(True, "**/tracedemo.py"), + )) + stats = snapshot.statistics("lineno") + + for stat in stats: + frame = stat.traceback[0] + print(stat) + print(linecache.getline(frame.filename, frame.lineno).strip()) + + tracemalloc.stop() + + +if __name__ == "__main__": + main() +``` + + +## 결과 스크린샷 +Screenshot 2024-05-20 at 8 23 20 PM + diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/8\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/8\354\243\274\354\260\250.md" new file mode 100644 index 0000000..10e08fb --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/8\354\243\274\354\260\250.md" @@ -0,0 +1,3 @@ +# 원하는 라이브러리 import 해보고, 참조 카운트가 어떻게 바뀌는지 출력해보기 + +Screenshot 2024-06-30 at 2 38 51 AM diff --git "a/8th_members/\352\271\200\355\225\204\353\252\250/9\354\243\274\354\260\250.md" "b/8th_members/\352\271\200\355\225\204\353\252\250/9\354\243\274\354\260\250.md" new file mode 100644 index 0000000..a638239 --- /dev/null +++ "b/8th_members/\352\271\200\355\225\204\353\252\250/9\354\243\274\354\260\250.md" @@ -0,0 +1,44 @@ +```python3 +import time +from multiprocessing import Pool + +# Define the CPU-bound task + + +def cpu_bound_task(n): + result = 1 + for i in range(1, n + 1): + result *= i + return result + +# Single-process version + + +def single_process(tasks): + results = [] + for task in tasks: + results.append(cpu_bound_task(task)) + return results + +# Multiprocessing version + + +def multi_process(tasks): + with Pool() as pool: + results = pool.map(cpu_bound_task, tasks) + return results + + +if __name__ == "__main__": + tasks = [100000 + i for i in range(20)] # Define tasks + + start = time.time() + single_process(tasks) + print("Single-process time:", time.time() - start) + + start = time.time() + multi_process(tasks) + print("Multiprocessing time:", time.time() - start) +``` +Screenshot 2024-06-30 at 2 18 40 PM + diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/10\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/10\354\243\274\354\260\250.md" new file mode 100644 index 0000000..93e100a --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/10\354\243\274\354\260\250.md" @@ -0,0 +1,39 @@ +# 10주차 + +## Port Scanner: Multi Threading - 멀티스레딩 + 스레드 개수 제한 +```python +import time +import socket +from concurrent.futures import ThreadPoolExecutor, as_completed + +timeout = 1.0 + +def check_port(host: str, port: int) -> int: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.settimeout(timeout) + result = sock.connect_ex((host, port)) + if result == 0: + return port + return None + +def main(): + start = time.time() + host = "localhost" # Replace with a host you own + open_ports = [] + + with ThreadPoolExecutor(max_workers=10) as executor: + futures = [executor.submit(check_port, host, port) for port in range(100, 200)] + + for future in as_completed(futures): + port = future.result() + if port is not None: + open_ports.append(port) + + for port in open_ports: + print(f"Port {port} is open") + print(f"Completed scan in {time.time() - start:.2f} seconds") + +if __name__ == '__main__': + main() +``` +

\ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/11\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/11\354\243\274\354\260\250.md" new file mode 100644 index 0000000..5a23a2b --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/11\354\243\274\354\260\250.md" @@ -0,0 +1,74 @@ +# 11주차 +## str type 분석 +```c +Objects/object.c + +INIT_TYPE(&PyUnicode_Type, "str"); +``` +- python의 str은 PyUnicode_Type 을 서용함 + +```c +Objects\unicodeobject.c + +PyTypeObject PyUnicode_Type = { + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "str", /* tp_name */ + sizeof(PyUnicodeObject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* Slots */ + (destructor)unicode_dealloc, /* tp_dealloc */ + 0, /* tp_vectorcall_offset */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_as_async */ + unicode_repr, /* tp_repr */ + &unicode_as_number, /* tp_as_number */ + &unicode_as_sequence, /* tp_as_sequence */ + &unicode_as_mapping, /* tp_as_mapping */ + (hashfunc) unicode_hash, /* tp_hash*/ + 0, /* tp_call*/ + (reprfunc) unicode_str, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | + Py_TPFLAGS_UNICODE_SUBCLASS, /* tp_flags */ + unicode_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + PyUnicode_RichCompare, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + unicode_iter, /* tp_iter */ + 0, /* tp_iternext */ + unicode_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + &PyBaseObject_Type, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + unicode_new, /* tp_new */ + PyObject_Del, /* tp_free */ +}; +``` +- type 정의 + +```c +/* Strings allocated through PyUnicode_FromUnicode(NULL, len) use the + PyUnicodeObject structure. The actual string data is initially in the wstr + block, and copied into the data block using _PyUnicode_Ready. */ +typedef struct { + PyCompactUnicodeObject _base; + union { + void *any; + Py_UCS1 *latin1; + Py_UCS2 *ucs2; + Py_UCS4 *ucs4; + } data; /* Canonical, smallest-form Unicode buffer */ +} PyUnicodeObject; + +``` +- 구조체 \ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/12\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/12\354\243\274\354\260\250.md" new file mode 100644 index 0000000..c9ec885 --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/12\354\243\274\354\260\250.md" @@ -0,0 +1,73 @@ +# 12주차 + +## unittest 사용해보기 +```python +import unittest + +def normalize(input_str): + """ + 인풋으로 받는 스트링에서 아래의 규칙으로 정규화된 스트링을 반환하는 함수입니다. + * 모든 단어들은 소문자로 변환됨 + * 띄어쓰기는 한칸으로 되도록 함 + * 앞뒤 필요없는 띄어쓰기는 제거함 + Parameters: + input_str (string): 영어로 된 대문자, 소문자, 띄어쓰기, 문장부호, 숫자로 이루어진 string + ex - " EXTRA SPACE " + Returns: + normalized_string (string): 정규회된 string + ex - 'extra space' + Examples: + >>> import text_processing as tp + >>> example = " EXTRA SPACE " + >>> tp.normalize(example) + 'extra space' + """ + out = input_str.lower() + out = out.strip() + while ' ' in out: + out = out.replace(' ', ' ') + return out + +class TestTextNormalize(unittest.TestCase): + def test_normalize(self): + test_str = "This is an example." + pred = normalize(test_str) + self.assertEqual(pred, "this is an example.") + + test_str = " EXTRA SPACE " + pred = normalize(test_str) + self.assertEqual(pred, "extra space") + + test_str = "THIS IS ALL CAPS!!" + pred = normalize(test_str) + self.assertEqual(pred, "this is all caps!!") + + test_str = " " + pred = normalize(test_str) + self.assertEqual(pred, "") + + test_str = "this is all lower space..." + pred = normalize(test_str) + self.assertEqual(pred, "this is all lower space...") + + test_str = " H e L l O !" + pred = normalize(test_str) + self.assertEqual(pred, "h e l l o !") + + test_str = "" + pred = normalize(test_str) + self.assertEqual(pred, "") + + test_str = "........" + pred = normalize(test_str) + self.assertEqual(pred, "........") + + test_str = "EX A M P LE" + pred = normalize(test_str) + self.assertEqual(pred, "ex a m p le") + + test_str = "AbCd EfGh IjKl MnOp" + pred = normalize(test_str) + self.assertEqual(pred, "abcd efgh ijkl mnop") +``` +

\ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/1\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/1\354\243\274\354\260\250.md" new file mode 100644 index 0000000..8310493 --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/1\354\243\274\354\260\250.md" @@ -0,0 +1,8 @@ +# 1주차 + +## CPython 소스코드 다운로드 및 환경 구성 +

+ +## 스터디에서 이루고 싶은 목표, 함께 하게 된 소감 +- 이번 스터디를 통해서 Python 동작 원리를 조금 더 깊게 이해해서, 사용하고 있는 코드들의 성능을 최적화 하고 싶습니다. +- CPython을 공부하려는 사람들을 위한 좋은 가이드북을 만들면 좋겠습니다. \ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/2\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/2\354\243\274\354\260\250.md" new file mode 100644 index 0000000..ac12377 --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/2\354\243\274\354\260\250.md" @@ -0,0 +1,8 @@ +# 2주차 + +## 컴파일 +

+ +## 새로운 문법 생성 +- pass 키워드에 LGTM을 추가 +

\ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/3\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/3\354\243\274\354\260\250.md" new file mode 100644 index 0000000..69c7bdd --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/3\354\243\274\354\260\250.md" @@ -0,0 +1,10 @@ +# 3주차 + +## CPython 인터프리터 실행 과정 코드 레벨로 이해하기 +

+ +## 파이썬 세션에서 runtime flag 확인하기 +

+ +## importlib.util.find_spec 함수를 사용해서 원하는 모듈의 위치를 찾아보기 +

\ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/4\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/4\354\243\274\354\260\250.md" new file mode 100644 index 0000000..9628d79 --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/4\354\243\274\354\260\250.md" @@ -0,0 +1,8 @@ +# 4주차 + +## instaviz로 AST 시각화 해보기 +

+

+ +## ‘거의 같음’ 연산자를 문법에 추가하고 AlE타입의 객체를 출력 해보기 +

diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/5\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/5\354\243\274\354\260\250.md" new file mode 100644 index 0000000..900e900 --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/5\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 5주차 + +## ‘거의 같음’ 연산자 구현 +

\ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/6\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/6\354\243\274\354\260\250.md" new file mode 100644 index 0000000..598fa53 --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/6\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 6주차 + +## 파이썬에서 프레임 객체 접근해보기 +

\ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/7\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/7\354\243\274\354\260\250.md" new file mode 100644 index 0000000..d936efc --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/7\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 7주차 + +## tracemalloc 모듈 사용해서 직접 메모리 확인해보기 +

\ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/8\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/8\354\243\274\354\260\250.md" new file mode 100644 index 0000000..029fcec --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/8\354\243\274\354\260\250.md" @@ -0,0 +1,4 @@ +# 8주차 + +## 원하는 라이브러리 import 해보고, 참조 카운트가 어떻게 바뀌는지 출력해보기 +

\ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/9\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\204\261\353\262\224/9\354\243\274\354\260\250.md" new file mode 100644 index 0000000..db1b902 --- /dev/null +++ "b/8th_members/\354\235\264\354\204\261\353\262\224/9\354\243\274\354\260\250.md" @@ -0,0 +1,31 @@ +# 9주차 + +## 간단한 CPU-Bound Job을 만들고 멀티프로세싱을 적용한 코드와 아닌 코드를 작성해보기 +```python +import time +import multiprocessing as mp + +pool_size = 10 + +def cpu_task(a=1): + time.sleep(1) + +def no_multiprocessing_run(): + start_time = time.time() + for _ in range(pool_size): + cpu_task() + end_time = time.time() + print(f"Duration without multiprocessing: {end_time - start_time} seconds") + +def multiprocessing_run(): + start_time = time.time() + with mp.Pool(pool_size) as p: + p.map(cpu_task, range(pool_size)) + end_time = time.time() + print(f"Duration with multiprocessing: {end_time - start_time} seconds") + +if __name__ == '__main__': + no_multiprocessing_run() + multiprocessing_run() +``` +

\ No newline at end of file diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/10_week.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/10_week.png" new file mode 100644 index 0000000..f7d405c Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/10_week.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/12_week.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/12_week.png" new file mode 100644 index 0000000..356ebab Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/12_week.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/1_week.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/1_week.png" new file mode 100644 index 0000000..244e4d7 Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/1_week.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/2_week_build.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/2_week_build.png" new file mode 100644 index 0000000..5c8edc1 Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/2_week_build.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/2_week_pass.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/2_week_pass.png" new file mode 100644 index 0000000..62b2413 Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/2_week_pass.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/3_week_find_spec.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/3_week_find_spec.png" new file mode 100644 index 0000000..514acd5 Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/3_week_find_spec.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/3_week_interpreter.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/3_week_interpreter.png" new file mode 100644 index 0000000..d8fea35 Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/3_week_interpreter.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/3_week_runtime_flag.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/3_week_runtime_flag.png" new file mode 100644 index 0000000..9c9fcbc Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/3_week_runtime_flag.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/4_week_1-1.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/4_week_1-1.png" new file mode 100644 index 0000000..5145259 Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/4_week_1-1.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/4_week_1-2.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/4_week_1-2.png" new file mode 100644 index 0000000..366b74d Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/4_week_1-2.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/4_week_2.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/4_week_2.png" new file mode 100644 index 0000000..8e8b41d Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/4_week_2.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/5_week.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/5_week.png" new file mode 100644 index 0000000..6172603 Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/5_week.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/6_week.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/6_week.png" new file mode 100644 index 0000000..804524b Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/6_week.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/7_week.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/7_week.png" new file mode 100644 index 0000000..c5a72da Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/7_week.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/8_week.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/8_week.png" new file mode 100644 index 0000000..a87a470 Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/8_week.png" differ diff --git "a/8th_members/\354\235\264\354\204\261\353\262\224/image/9_week.png" "b/8th_members/\354\235\264\354\204\261\353\262\224/image/9_week.png" new file mode 100644 index 0000000..a889d10 Binary files /dev/null and "b/8th_members/\354\235\264\354\204\261\353\262\224/image/9_week.png" differ diff --git "a/8th_members/\354\235\264\354\232\251\354\232\260/10\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\232\251\354\232\260/10\354\243\274\354\260\250.md" new file mode 100644 index 0000000..76fecde --- /dev/null +++ "b/8th_members/\354\235\264\354\232\251\354\232\260/10\354\243\274\354\260\250.md" @@ -0,0 +1,47 @@ +### 멀티 쓰레드 요약 +1. 각 쓰레드는 각자의 Program Counter와 Stack을 갖기 때문에 + 동시에 다른 작업을 처리할 수 있다. +2. **Thread Safety**를 위해서 CPython에서는 GIL을 사용한다. +3. GIL로 인해서 CPU-Bound 작업에서는 멀티 쓰레드의 이점을 얻지 못하지만, + I/O-Bound 작업에서는 멀티 쓰레딩을 적극적으로 활용할 수 있다. +4. 이를 위해서 `Py_BEGIN_ALLOW_THREADS`와 `Py_END_ALLOW_THREADS` + 매크로가 실제 구현에 사용된다. 내장 패키지 구석구석에서 해당 구현을 확인할 수 있다. +5. Thread는 프로세스와 메모리를 공유하기 때문에 + 프로세스를 새로 생성하는 것 보다는 오버헤드가 적다. + + +

+ +#### 코루틴 +→ 실행을 중단하고 재개할 수 있는 함수, 특정 시점에서 작업을 중단하고 다른 작업을 수행할 수 있다. +→ 호출자와 호출된 함수 사이의 제어 흐름이 상호작용 +→ 비동기 프로그래밍에서 사용 + +
+ +#### 네이티브 코루틴 +- 함수 앞에 `async` 키워드를 명시하여 코루틴을 반환함을 명시 +- `asyncio.run()`을 통해 코루틴 객체 생성 +- 실행 순서 + - 1) 새 이벤트 루프를 시작 + - 2) 코루틴 객체를 Task로 감싸기 + - 3) Task가 완료될 때 까지 실행할 CallBack을 설정 + - 4) Task가 완료될 때 까지 루프를 반복 + - 5) 결과 반환 + +장점 +- 여러 코루틴 동시 실행 가능 +- 코루틴 객체를 다른 함수의 인자로 사용 가능 + - 코루틴 객체를 서로 연결하여 연쇄적으로 처리하거나 순차적으로 생성 가능 + +※ 이벤트 루프 +- 비동기 코드를 연결하는 접착제 역할 + + +


+ +### Port Scanner 예제 실행 + +좌: 멀티 쓰레드, 우: 멀티 쓰레드(쓰레드 수 제한) + + \ No newline at end of file diff --git "a/8th_members/\354\235\264\354\232\251\354\232\260/12\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\232\251\354\232\260/12\354\243\274\354\260\250.md" new file mode 100644 index 0000000..a4d5cda --- /dev/null +++ "b/8th_members/\354\235\264\354\232\251\354\232\260/12\354\243\274\354\260\250.md" @@ -0,0 +1,96 @@ +### Test Case 만들기 +``` +Project + |- tests + |- __init__.py + |- test_normalize.py + |- text_processing.py +``` + + +

+ +``` python +def normalize(input_str): + out = input_str.lower() + out = out.strip() + while ' ' in out: + out = out.replace(' ', ' ') + return out +``` + +
+ +``` python +import unittest +from text_processing import normalize + + +class TestTextNormalize(unittest.TestCase): + def test_normalize(self): + test_str = "This is an example." + pred = normalize(test_str) + self.assertEqual(pred, "this is an example.") + + test_str = " EXTRA SPACE " + pred = normalize(test_str) + self.assertEqual(pred, "extra space") + + test_str = "THIS IS ALL CAPS!!" + pred = normalize(test_str) + self.assertEqual(pred, "this is all caps!!") + + test_str = " " + pred = normalize(test_str) + self.assertEqual(pred, "") + + test_str = "this is all lower space..." + pred = normalize(test_str) + self.assertEqual(pred, "this is all lower space...") + + test_str = " H e L l O !" + pred = normalize(test_str) + self.assertEqual(pred, "h e l l o !") + + test_str = "" + pred = normalize(test_str) + self.assertEqual(pred, "") + + test_str = "........" + pred = normalize(test_str) + self.assertEqual(pred, "........") + + test_str = "EX A M P LE" + pred = normalize(test_str) + self.assertEqual(pred, "ex a m p le") + + test_str = "AbCd EfGh IjKl MnOp" + pred = normalize(test_str) + self.assertEqual(pred, "abcd efgh ijkl mnop") +``` + + +

+ + +``` +# tests 디렉토리 내 모든 테스트 파일 실행 +$ python -m unittest discover tests -v +``` + +``` +# 특정 테스트 파일 실행 +$ python -m unittest tests.test_normalize -v +``` + +``` +# 특정 테스트 스위트 실행 +$ python -m unittest tests.test_normalize.TestTextNormalize +``` + +``` +# 특정 테스트 케이스 실행 +$ python -m unittest tests.test_normalize.TestTextNormalize.test_normalize +``` + + diff --git "a/8th_members/\354\235\264\354\232\251\354\232\260/13\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\232\251\354\232\260/13\354\243\274\354\260\250.md" new file mode 100644 index 0000000..ae52e37 --- /dev/null +++ "b/8th_members/\354\235\264\354\232\251\354\232\260/13\354\243\274\354\260\250.md" @@ -0,0 +1,31 @@ +### 1. pdb 실행 + +|shortcut|설명| +|---|---| +|`l`|주변 소스코드를 출력하며 현재 라인이 화살표로 나옴| +|`n`|다음 문장으로 이동| +|`s`|Step Into| +|`w`|함수의 call stack 출력| +|`s`|현재 함수의 argument들을 출력| + + + +


+ +### 2. CProfile 예제 파일 직접 생성해서 실행해보기 + +``` bash +$ python -m cProfile -o output.pstat portscanner_multithread.py +``` + + + + +
+ +``` bash +$ pip install snakeviz +$ python -m snakeviz output.pstat +``` + + \ No newline at end of file diff --git "a/8th_members/\354\235\264\354\232\251\354\232\260/1\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\232\251\354\232\260/1\354\243\274\354\260\250.md" new file mode 100644 index 0000000..52c4461 --- /dev/null +++ "b/8th_members/\354\235\264\354\232\251\354\232\260/1\354\243\274\354\260\250.md" @@ -0,0 +1,83 @@ +# 1주차 +### 목차 +1. [CPython 소스코드 다운로드 및 환경 구성](#cpython-소스코드-다운로드-및-환경-구성) + 1-1. [VSCode 코드 구성하기](#vscode-코드-구성하기) + 1-2. [작업과 실행 파일 설정](#작업과-실행-파일-설정) + 1-3. [환경 구성 켑처](#환경-구성-결과) +2. [스터디에서 이루고 싶은 목표 & 함께 하게 된 소감](#스터디에서-이루고-싶은-목표--함께-하게-된-소감) + +

+ +## CPython 소스코드 다운로드 및 환경 구성 +### VSCode 코드 구성하기 +VSCode는 온라인 플러그인 마켓 플레이스를 제공하는 확장 가능한 코드 편집기이다. +통합 git 인터페이스를 제공하며, C와 파이썬 모두를 지원하기 때문에 CPython을 위한 좋은 선택이 될 수 있다. + +Extensions 패널에 접근하여 `ms-vscode.cpptools`와 같은 고유 식별자로 확장을 검색할 수 있다. +C/C++ for Visual Studio Code를 클릭하여 다운로드하도록 하자. + + +또한 권장되는 확장은 아래와 같다. +|Extension|Description| +|--|--| +|C/C++ (`ms-vscode.cpptools`)|인텔리센스, 디버깅, 코드 강조 등의 C/C++ 지원을 제공| +|Python (`ms-python.python`)|파이썬 코드 편집, 디버깅, 탐색 등의 파이썬 지원을 제공| +|reStructuredText (`lextudio.restructuredtext`)|CPython 문서에 사용되는 reStructuredtext에 대한 지원을 제공| +|Task Explorer (`spmeesseman.vscode-taskexplorer`)|make 작업을 편리하게 실행할 수 있는 Task Explorer 패널을 Explorer 탭 안에 추가| + + +

+ +### 작업과 실행 파일 설정 +VSCode는 작업 디렉터리 내부의 `.vscode` 폴더를 작업 공간 설정에 사용한다. +폴더가 없으면 새로 만들고 다음 파일들을 추가해서 작업 공간을 설정할 수 있다. + +- 프로젝트 실행 명령에 대한 `tasks.json` +- 디버거를 위한 `launch.json` +- 기타 플러그인을 위한 파일 + +`tasks.json` 파일에 작업을 등록할 수 있다. + +```json +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "type": "shell", + "group": { + "kind": "build", + "isDefault": true + }, + "windows": { + "command": "PCBuild/build.bat", + "args": ["-p", "x64", "-c", "Debug"] + }, + "linux": { + "command": "make -j2 -s" + }, + "osx": { + "command": "make -j2 -s" + } + } + ] +} +``` + +

+ +### 환경 구성 결과 + + + + +


+ +## 스터디에서 이루고 싶은 목표 & 함께 하게 된 소감 +이번 스터디를 통해 Python 언어를 더 깊이 있게 이해하고, +이 스터디를 마친 후에는 Python을 원하는 기능 및 스펙에 맞게 +입맛대로 커스텀 할 수 있는 엔지니어로 성장하기 위한 초석을 다지고 싶습니다. + +이번 CPython 스터디에 참여하여 관심사가 비슷한 분들과 함께 할 수 있게 되어 기쁘게 생각하고 있습니다. +모든 분들이 이번 스터디를 통해 각자 성취, 혹은 원하는 바를 이룰 수 있었으면 좋겠습니다. +앞으로 스터디 기간 동안 잘 부탁드립니다. 감사합니다🙂 \ No newline at end of file diff --git "a/8th_members/\354\235\264\354\232\251\354\232\260/2\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\232\251\354\232\260/2\354\243\274\354\260\250.md" new file mode 100644 index 0000000..5e49d62 --- /dev/null +++ "b/8th_members/\354\235\264\354\232\251\354\232\260/2\354\243\274\354\260\250.md" @@ -0,0 +1,98 @@ +# 2주차 +### 목차 +1. [macOS에서 CPython 컴파일하기](#macos에서-cpython-컴파일하기) +2. [문법 다시 생성하기 (pass 키워드 변경해보기) 부분 원하는 키워드 다른걸로 바꿔보기 (결과 화면 캡쳐)](#문법-다시-생성하기-pass-키워드-변경해보기-부분-원하는-키워드-다른걸로-바꿔보기-결과-화면-캡쳐) + +

+ +### macOS에서 CPython 컴파일하기 +macOS에서 CPython을 컴파일하려면 어플리케이션과 라이브러리가 추가로 필요하다. +그 중 Command Line Tools는 필수적인 C 컴파일러 툴킷으로 +터미널로 설치하고 앱스토어에서 업데이트 할 수 있다. + +다음 명령을 실행해 C 컴파일러 툴킷을 설치하면 +git, make, GNU C 컴파일러 등의 도구들이 설치된다. + +``` +$ xcode-select --install +``` + + + +

+ +PyPI에서 패키지를 받아 설치하려면 OpenSSL도 필요하다. +HomeBrew로 macOS에 간단하게 OpenSSL을 설치할 수 있다. + +brew install 명령으로 CPython에 필요한 의존성을 설치하자. + +``` +$ brew install openssl xz zlib gdbm sqlite +``` + +

+ +zlib이 설치된 위치를 지정하고 구성 작업을 실행하자. +이 작업은 한 번만 실행하면 된다. + +``` +# cd ~/your/cpython/path + +$ CPPFLAGS="-I$(brew --prefix zlib)/include" \ +LDFLAGS="-L$(brew --prefix zlib)/lib" \ +./configure --with-openssl=$(brew --prefix openssl) \ +--with-pydebug +``` + +

+ +./configure가 저장소 최상단에 위치한 Makefile이 빌드 과정을 자동화한다. +다음 명령어로 CPython 바이너리를 빌드하자. + +``` +$ make -j2 -s +``` + +


+ +### 문법 다시 생성하기 (pass 키워드 변경해보기) 부분 원하는 키워드 다른걸로 바꿔보기 (결과 화면 캡쳐) +CPython3.9 부터 도입된 새로운 PEG 생성기인 pegen을 테스트해 보기 위해 문법 일부를 변경해보자. +Grammar → python.gram에서 간단한 정의인 small_stmt를 찾아 수정해보자. +※ small_stmt: 단일 독립 실행 가능한 구성요소 + +``` +small_stmt[stmt_ty] (memo): + | assignment + | e=star_expressions { _Py_Expr(e, EXTRA) } + | &'return' return_stmt + | &('import' | 'from') import_stmt + | &'raise' raise_stmt + | 'pass' { _Py_Pass(EXTRA) } + | &'del' del_stmt + | &'yield' yield_stmt + | &'assert' assert_stmt + | ('break' | 'heartbreaker') { _Py_Break(EXTRA) } + | 'continue' { _Py_Continue(EXTRA) } + | &'global' global_stmt + | &'nonlocal' nonlocal_stmt +``` + +

+ +CPython의 자동 문법 재생성 스크립트를 사용해 문법 파일을 다시 빌드하자. +``` +$ make regen-pegen +``` + +

+ +CPython을 새 파서 테이블과 같이 컴파일하면 새 문법이 추가된다. +이전 장에서 소개한 운영 체제 별 컴파일 방법을 그대로 실행하면 된다. + +``` +$ make -j2 -s +``` + +

+ + \ No newline at end of file diff --git "a/8th_members/\354\235\264\354\232\251\354\232\260/3\354\243\274\354\260\250.md" "b/8th_members/\354\235\264\354\232\251\354\232\260/3\354\243\274\354\260\250.md" new file mode 100644 index 0000000..fe95c4a --- /dev/null +++ "b/8th_members/\354\235\264\354\232\251\354\232\260/3\354\243\274\354\260\250.md" @@ -0,0 +1,207 @@ +# 3주차 +### 목차 +1. [구성 상태](#구성-상태) + - [딕셔너리 초기화 구성](#딕셔너리-초기화-구성) + - [연관된 소스 파일 목록](#연관된-소스-파일-목록) + - [런타임 구성 구조체](#런타임-구성-구조체) + - [명령줄로 런타임 구성 설정하기](#명령줄로-런타임-구성-설정하기) +2. [빌드 구성](#빌드-구성) +3. [입력에서 모듈 만들기](#입력에서-모듈-만들기) + - [연관된 소스 파일 목록](#연관된-소스-파일-목록) +4. [3주차 미션](#3주차-미션) + - [CPython 인터프리터 실행 과정 코드 레벨로 이해하기](#cpython-인터프리터-실행-과정-코드-레벨로-이해하기) + - [파이썬 세션에서 Runtime Flag 확인하기](#파이썬-세션에서-runtime-flag-확인하기) + - [importlib.util.find_spec 함수를 사용해서 원하는 모듈의 위치를 찾아보기](#importlibutilfind_spec-함수를-사용해서-원하는-모듈의-위치를-찾아보기) + + +


+ +### 구성 상태 +CPython 런타임은 사용자 옵션구성(Configuration)을 설정한다. +특히 **Configuration**은 세 부분으로 나뉘어 있다. + +- `PyPreConfig` 딕셔너리 초기화 Configuration +- `PyConfig` 런타임 Configuration +- CPython 인터프리터에 같이 컴파일된 Configuration + +여기서 `PyPreconfig`, `PyConfig` 구조체는 +`Include/cpython/initconfig.h`에서 정의한다. + +

+ +#### 딕셔너리 초기화 구성 +**딕셔너리 초기화 Configuration**은 사용자 환경 또는 운영체제와 관련된 Configuration이기에 +런타임 Configuration과는 구분된다. + +다음은 `PyPreConfig`의 세 가지 주요 기능이다. +1. 파이썬 메모리 할당자 설정하기 +2. `LC_CTYPE` 로켈(locale)을 시스템 또는 사용자 선호 로켈로 구성 +3. UTF-8 모드로 설정 + +> Locale : 특정 지역, 국가, 또는 문화권에서 사용하는 언어 등과 같은 지역설정을 의미함. (ex. `ko-KR`) + + +`PyPreConfig` 구조체는 다음과 같은 `int` 타입 필드들을 포함한다. + +| 필드 | 설명 | +| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `allocator` | `PYMEM_ALLOCATOR_MALLOC`와 같은 값을 사용해서 메모리 할당자를 선택한다.
`./configure --help`를 실행해 메모리 할당자에 대한 추가 정보를 얻을 수 있다. | +| `configure_locate` | `LC_CTYPE` 로켈을 사용자 선호 로캘로 설정한다.
`0`으로 설정하면 `coerce_c_locale`과 `coerce_c_locale_warn`을 `0`으로 설정한다. | +| `coerce_c_locale` | `2`로 설정하면 C 로켈을 강제로 적용한다.
`1`로 설정하면 `LC_CTYPE`을 읽은 후 강제로 적용할지 결정한다. | +| `coerce_c_locale_warn` | `0`이 아니면 C 로켈이 강제로 적용될 때 경고가 발생한다. | +| `dev_mode` | 개발 모드를 활성화한다. | +| `isolated` | 격리 모드를 활성화한다. `sys.path`에 스크립트 디렉터리와
사용자의 사이트 패키지 디렉터리가 포함되지 않는다. | +| `legacy_windows_fs_encoding` | `0`이 아니면 UTF-8 모드를 비활성화하고 파이썬 파일 시스템 인코딩을 `mbcs`로 설정한다. | +| `parse_argv` | `0`이 아니면 명령줄 인자를 사용한다. | +| `use_environment` | `0`보다 큰 값이면 환경 변수를 사용한다. | +| `utf8_mode` | `0`이 아니면 UTF-8 모드를 활성화한다. | + +
+ +`Include/cpython/initconfig.h`에서 `PyPreConfig` 구조체를 찾아볼 수 있다. + +

+ +#### 연관된 소스 파일 목록 +다음은 `PyPreConfig`와 연관된 소스 파일 목록이다. + +| 파일 | 용도 | +| ---------------------- | ------------------------------------------------------- | +|`Python/initconfig.c` | 시스템 환경에서 불러온 구성을 명령줄 플래그와 결합한다. | +|`Include/cpython/initconfig.h` | 초기화 구성 구조체를 정의한다. | + +

+ +#### 런타임 구성 구조체 +`PyConfig`이라 불리는 런타임 Configuration 구조체는 다음과 같은 값들을 포함한다. +- '디버그'나 '최적화'와 같은 실행 모드 플래그 +- 스크립트 파일이나 `stdin`, 모듈 등 실행 모드 +- `-X