├── .gitignore ├── README.md └── courses └── novice ├── README.md └── exercises ├── week1 ├── 1.py ├── 2.py └── 3.py ├── week2 ├── 1.py ├── 2.py ├── 3.py ├── 4.py └── 5.py └── week3 ├── 1.py ├── 2.py ├── 3.py ├── 4.py ├── 5.py └── 6.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *~ 3 | *.swp 4 | *.bak 5 | *egg-info* 6 | build 7 | dist 8 | bdist 9 | debian/files 10 | MANIFEST 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Learn Python In Hacker Way (用駭客的方式學 Python) 2 | 3 | ## 前言 4 | 5 | 我是 Hychen。 6 | 7 | 因為有人想學 Python ,所以我就來教了,這裡是教學上用到的教材。 8 | 在這門課除了教你 Python , 你還會學到一些軟體開發中會用到的工具, 9 | 以及開放源碼/自由軟體社群的工作模式。 10 | 11 | 本教材適合一人自學或是一人教多人使用。 12 | 13 | *聲明* 14 | 15 | 1. 若有任何錯誤,歡迎自由 Patch/Fork。 16 | 1. 網路上的連結總會失效,學生們需具備自行修復的能力。 17 | 18 | ## 目標 19 | 20 | 學 Python ,學到什麼程度就看個人努力了。 21 | 22 | ## 文化與哲學 23 | 24 | 這邊說得 Hacker 指得是"泛指任何一類事務或領域中的專家或狂熱份子。" 25 | 開始前建議閱讀下面這兩篇 26 | 27 | - [如何成為駭客][1] 28 | - [提問的智慧][2] 29 | 30 | 下面這個是推薦的[Coding Style][6],有時間再讀 31 | 32 | - [PEP 8 - Coding Style][7] 33 | - [字正腔圓說Python](http://yukuan.blogspot.com/2006/11/be-pythonic-python.html) 34 | 35 | ## 如何使用本教材 36 | 37 | 你可以照著本教材上頭列的連結自學,也可以找個熟Python的人利用這份教材來指導你。 38 | 後面我將用`學徒`來稱呼想學 Python 的人,`老師` 來稱呼指導學生的人。 39 | 40 | `學徒`將會需要使用Git來取得最新的內容, 還有繳交指定作業給老師做Code Review。 41 | 如果`學徒`或`老師`不曾用過Git,請先閱讀 [ihower][3] 的[Git and Github 演講投影片][4]。 42 | 43 | 在閱讀上面提及的投影片後,你需要了解怎麼使用下面的git commands: 44 | 45 | - git clone 46 | - git add 47 | - git commit 48 | - git pull 49 | - git push 50 | 51 | 課程講義依難度分為 52 | 53 | - 新手(Novice): 54 | 熟悉基本資料結構以及迴圈,以及撰寫 Function,內容在`courses/novice/README.md` 55 | - 學徒(Apprentice): 56 | 能使用Function, Class 來維護較大型的程式, 一些常用的函式庫,以及撰寫測試程式,內容在`courses/apprentice/README.md` (尚未完成) 57 | - 老手(Adept): 58 | 使用Decorator, Generator, Meta Class 來加速開發速度,熟悉特定領域的函式庫使用,例如做GUI的人會熟悉PyGTK, PyQT。 59 | 內容在`courses/adept/README.md` (尚未完成) 60 | - 專家(Expert): 無法提供,因為我不是 61 | - 大師(Master): 無法提供,因為我不是 62 | 63 | 在學習的過程中,你可以使用`pydoc`來查Python文件,例如我想知道str.replace怎麼用,我就打 64 | 65 | ``` 66 | $ pydoc str.replace 67 | ``` 68 | 69 | 另一種查文件的方式是在Interpreter中打`help`,像這樣 70 | 71 | ``` 72 | Python 2.7.2+ (default, Oct 4 2011, 20:03:08) 73 | [GCC 4.6.1] on linux2 74 | Type "help", "copyright", "credits" or "license" for more information. 75 | >>> help(str.replace) 76 | ``` 77 | 78 | ## 開始 79 | 80 | 1. `老師`在 github 上 fork 此專案。 81 | 1. `學徒`在 github 上 fork `老師`的專案。 82 | 1. `學徒`依據課程大綱讀完講義上指定的閱讀項目,並且寫完指定的習題 83 | 1. `學徒`把指定的作業commit後,push 進自己的專案 84 | 1. `老師`Review`學徒的code,引導`學徒`思考寫出更好的code, 老師可以用 github 的 gist 來貼source code. 85 | 86 | ## 作業繳交方式 87 | 88 | 每個課程下面都有一個`exercises`的目錄,下面會有各週的作業。 作業的檔名會是`.py`結尾, 89 | 學徒寫完作業後,commit 進自己的專案,並且在`老師`的專案開一個Issue Ticket,通知老師Review 程式碼。 90 | 91 | [1]: http://www.angelfire.com/ok/leekawo/hacker.htm 92 | [2]: https://code.google.com/p/smartquestions/wiki/WhenYouAsk 93 | [3]: http://ihower.tw/blog/about 94 | [4]: http://ihower.tw/blog/archives/5391 95 | [5]: http://help.github.com/send-pull-requests/ 96 | [6]: http://mmdays.com/2007/04/24/coding-style/ 97 | [7]: http://www.python.org/dev/peps/pep-0008/ 98 | -------------------------------------------------------------------------------- /courses/novice/README.md: -------------------------------------------------------------------------------- 1 | # 新手課程 2 | 3 | 當學會爬說語(Python)後,你就不是麻瓜了 :) 4 | 5 | ## 開始之前 6 | 7 | 若你之前沒有學過任何程式語言,你可能會好奇什麼是程式。 8 | 9 | 程式其實就是成一連串的命令。 10 | 11 | 如果程式設計師是法師,那麼程式碼就是咒語,每個咒語都有不同的效果。 12 | 而在電腦執行程式碼就是用咒語施放法術。 13 | 14 | 咒語可以被抄寫成捲軸,想當然爾,程式碼也可以寫進文字檔,等需要時再使用。 15 | 那麼我們,也就是程式設計師是怎麼去設計程式呢? 首先,你必須有個目的。 16 | 然後確定需要什麼資料輸入,要產生的結果是什麼。 17 | 18 | 以買菜為例。 小明的媽媽叫他去買菜,對小明的吩咐是這樣的 19 | 20 | 我拿1000元給你,如果菜的單價小於100塊,就買吧! 21 | 22 | 要把這轉換成程式碼,先思考一件事情要達成,必須拆成幾個步驟,再想辦法把他翻成英文, 23 | 你就獲得了最基本的邏輯架構,通常稱之為[pseudocode][1](虛擬碼)。 24 | 25 | Python 的語法特性,大致上可以讓你"我手寫我口"。 26 | 27 | 本課程完成後,你會學會 28 | 29 | - 資料型別: int, float, str, unicode, list, dict 30 | - 運算子: ==, >=, <=, >=, >, <, !, not, or , and 31 | - 控制: if..else, if..elif, if..continue, if..break 32 | - 迴圈: while, for 33 | - 輸入輸出print, raw_input 34 | 35 | ## 大綱 36 | 37 | ### 第一週 (8小時) : 第一隻程式以及字串 38 | 39 | 因為我們為非英文語系使用者者,所以相當容易遇到編碼問題。 40 | 這一週主要學習 Python 裡面的字串以及編碼問題。 41 | 42 | #### 請閱讀 43 | 44 | - [電腦做什麼事- 與直譯器互動](http://pydoing.blogspot.com/2008/10/blog-post_04.html) 45 | - [Victor Python 介紹](http://python.ez2learn.com/intro.html) 46 | - [Python 2.7 Tutorial - Using Interpreter](http://docs.python.org/tutorial/interpreter.html) 47 | - [Victor Python 入門][1] 裡面的*註解*,*變數*,*輸入與輸出*,*字串* 48 | - [Python 2.7 Tutorial - Strings](http://docs.python.org/tutorial/introduction.html#strings) 49 | - [Victor - 瞭解Unicode](http://python.ez2learn.com/basic/unicode.html) 50 | 51 | #### 完成作業 52 | 53 | - `courses/novice/exercises/week1/1.py` 54 | - `courses/novice/exercises/week1/2.py` 55 | - `courses/novice/exercises/week1/3.py` 56 | 57 | #### 選讀 58 | 59 | - [PyCon US 2012 - Pragmatic Unicode, or, How do I stop the pain?](http://pyvideo.org/video/948/pragmatic-unicode-or-how-do-i-stop-the-pain) 60 | - [All About Python and Unicode](http://boodebr.org/main/python/all-about-python-and-unicode) 61 | 62 | ### 第二週 (8小時) 63 | 64 | 這一週開始後的作業會採用*測試先行*(Test-Driven)的方式來引導, 那何謂測試先行呢? 65 | 其時就是你先把預期的結果寫出來,再想辦法把程式碼寫出。 66 | 67 | 最簡單的撰寫test 方式是使用斷言(assertion), 68 | 等之後介紹過 function 會再介紹到其他更強大的測試工具。 69 | 70 | 下面是個範例 71 | 72 | ``` 73 | Python 2.7.2+ (default, Oct 4 2011, 20:03:08) 74 | [GCC 4.6.1] on linux2 75 | Type "help", "copyright", "credits" or "license" for more information. 76 | >>> answer = 1 77 | # assert 測試, 錯誤訊息 78 | >>> assert answer == 2 79 | Traceback (most recent call last): 80 | File "", line 1, in 81 | AssertionError 82 | ``` 83 | 84 | 需要看懂上面在做什麼你需要讀完下面的 'Boolean Practice' 85 | 86 | #### 請閱讀 87 | 88 | - [電腦做什麼事 - 真假世界](http://pydoing.blogspot.com/2008/10/blog-post_6123.html) 89 | - [數值運算](http://ez2learn.com/index.php/python-tutorials/python-tutorials/165-2009-02-11-13-09-18) 90 | - [串列](http://ez2learn.com/index.php/python-tutorials/python-tutorials/166-list) 91 | - [切片](http://ez2learn.com/index.php/python-tutorials/python-tutorials/167-slice) 92 | - [Tuple](http://caterpillar.onlyfun.net/Gossip/Python/TupleType.html) 93 | - [if 判斷句](http://ez2learn.com/index.php/python-tutorials/python-tutorials/171-if) 94 | - [Learn Python in Hard Way: Boolean Practice](http://learnpythonthehardway.org/book/ex28.html) 95 | - [More conditions](http://docs.python.org/tutorial/datastructures.html#more-on-conditions) 96 | - [break and continue Statements, and else Clauses on Loops](http://docs.python.org/tutorial/controlflow.html#break-and-continue-statements-and-else-clauses-on-loops) 97 | 98 | 註: python 裡的 True 在比較時會變成數字的1, False 會變成數值0, None 則就是 None, 你可以想一下面的答案是什麼 99 | 100 | - 1 == True 101 | - 1 is True 102 | - 0 == False 103 | - 0 is False 104 | - None == True 105 | - None is True 106 | - None == False 107 | - None is False 108 | 109 | 註: 要判斷一個元素有沒有在list 裡面可以用`in`, 要判斷一個字有沒有在一個字串內, 也可以用`in` 110 | 111 | Python 2.7.2+ (default, Oct 4 2011, 20:03:08) 112 | [GCC 4.6.1] on linux2 113 | Type "help", "copyright", "credits" or "license" for more information. 114 | >>> a=range(1,5) 115 | >>> 5 in a 116 | False 117 | >>> 4 in a 118 | True 119 | >>> a 120 | [1, 2, 3, 4] 121 | >>> '5' in a 122 | False 123 | >>> '4' in a 124 | False 125 | >>> '4' in '4string' 126 | True 127 | 128 | 129 | - [for 迴圈](http://ez2learn.com/index.php/python-tutorials/python-tutorials/172-for) 130 | 131 | note: 在 python 裡的for 指的是foreach, 如果你要真正的for, 可以用下面的方法來類比 132 | 133 | for index in range(0,5): 134 | print index 135 | 136 | # 輸出為 137 | # 0 138 | # 1 139 | # 2 140 | # 3 141 | # 4 142 | # 5 143 | 144 | range 是一個function, 會產生一個[0,1,2,3,4] 的陣列, 細節請`pydoc range` 145 | 146 | 而如果你想要取得元素的index, 可以使用`enumerate`, 147 | 148 | mylist = [1,2,3,4,5,6] 149 | for index, value in enumerate(mylist): 150 | print index, value 151 | 152 | # 下面是結果 153 | # 0 1 154 | # 1 2 155 | # 2 3 156 | # 3 4 157 | # 4 5 158 | # 5 6 159 | 160 | - [while 迴圈](http://ez2learn.com/index.php/python-tutorials/python-tutorials/173-while) 161 | - [字典](http://ez2learn.com/index.php/python-tutorials/python-tutorials/168-dictionary) 162 | - [Dictionaries](http://docs.python.org/tutorial/datastructures.html#dictionaries) 163 | - [Looping Techniques](http://docs.python.org/tutorial/datastructures.html#looping-techniques) 164 | 165 | #### 選讀 166 | 167 | - [軟體設計必讀經典(11)反覆測試與修正,讓錯誤消失](http://www.ithome.com.tw/itadm/article.php?c=47536) 168 | 169 | #### 完成作業 170 | 171 | - `courses/novice/exercises/week2/1.py` 172 | - `courses/novice/exercises/week2/2.py` 173 | - `courses/novice/exercises/week2/3.py` 174 | - `courses/novice/exercises/week2/4.py` 175 | - `courses/novice/exercises/week2/5.py` 176 | 177 | ### 第三週 (8小時) 178 | 179 | 工欲善其事, 必先力其器。如果不會用debugger,就好像人類不會用火一樣。 180 | Python 的 debugger 叫*PDB*,雖然沒有*GDB*那麼強大,但也堪用了。 181 | 182 | 本週你需要學會pdb, 進階的 list, dict 運用還有定義 function. 183 | 除此之外,會要熟撚`map`, `reduce`, filter`這三個非常有用的functional programming tool(在這個難度, 你可先不用懂什麼叫做functional programming)。 184 | 185 | 在 Python 裡面, Funciton 是*First-Class Function*。以新手來說, 只要記得有下列特性 186 | 187 | 1. Function 可以被當成 Funciton 的參數傳遞 188 | 1. Function 的回傳值可以是 Function 189 | 1. Function 可以被指派到變數 190 | 1. Function 可以不用指定名稱, 此類 Function 稱為*匿名函式*, 在 Python 裡使用`lambda`關鍵字定義 191 | 192 | 至於Closure在這個難度可以不用知道這是什麼. 193 | 194 | #### 請閱讀 195 | 196 | - [More on List](http://docs.python.org/tutorial/datastructures.html#more-on-lists) 197 | - [Sets](http://docs.python.org/tutorial/datastructures.html#sets) 198 | - [Dict Comprehensions](http://www.python.org/dev/peps/pep-0274/) 199 | - [Define Function](http://docs.python.org/tutorial/controlflow.html#defining-functions) 200 | - [More on Define Funciton](http://docs.python.org/tutorial/controlflow.html#more-on-defining-functions) 201 | - [How to debug](http://hcliao.twbbs.org/signal-processing-using-python/how-to-debug) 202 | - [Debuuging in Python](http://pythonconquerstheuniverse.wordpress.com/category/python-debugger/) 203 | 204 | #### 選讀 205 | 206 | - [Python Official Document - PDB](http://docs.python.org/library/pdb.html) 207 | - [First Class Function in Wikipidia](https://en.wikipedia.org/wiki/First-class_function) 208 | - [Closure in Wikipidia](http://en.wikipedia.org/wiki/Closure_(computer_science)) 209 | - [Closure 簡介](http://wiki.python.org.tw/Python/Cookbook/Closure) 210 | 211 | #### 完成作業 212 | 213 | - `courses/novice/exercises/week1/1.py` 214 | - `courses/novice/exercises/week1/2.py` 215 | - `courses/novice/exercises/week1/3.py ` 216 | - `courses/novice/exercises/week1/4.py` 217 | - `courses/novice/exercises/week1/5.py` 218 | - `courses/novice/exercises/week1/6.py` 219 | 220 | ### 第四週 (8小時) 221 | 222 | ### 第五週 (8小時) 223 | 224 | [1]: https://en.wikipedia.org/wiki/Pseudocode 225 | [2]: http://ez2learn.com/index.php/python-tutorials/python-tutorials 226 | [3]: http://python.ez2learn.com/basic.html 227 | -------------------------------------------------------------------------------- /courses/novice/exercises/week1/1.py: -------------------------------------------------------------------------------- 1 | """ 2 | 題目: 3 | 4 | 變數 str1 是句文言文,去掉空白後加上"我愛紅娘",並且列印出來 5 | """ 6 | str1 = ' 《五音集韻》說:「人死為鬼,人見懼之;鬼死為魙,鬼見怕之。」 ' 7 | -------------------------------------------------------------------------------- /courses/novice/exercises/week1/2.py: -------------------------------------------------------------------------------- 1 | """ 2 | 題目: 3 | 4 | 變數 str1 是句文言文,去掉前面的空白後,在'人死為鬼'後面插入英文字母A,並列印出來 5 | 輸出應該為"《五音集韻》說:「人死為鬼A,人見懼之;鬼死為魙,鬼見怕之。」 " 6 | 7 | 提示: 使用str.split或是strings slice notation 8 | """ 9 | str1 = ' 《五音集韻》說:「人死為鬼,人見懼之;鬼死為魙,鬼見怕之。」 ' 10 | -------------------------------------------------------------------------------- /courses/novice/exercises/week1/3.py: -------------------------------------------------------------------------------- 1 | """ 2 | 題目: 3 | 4 | 寫一隻程式讓使用者可以輸入字串,顯示其 Unicode,其輸出如下 5 | 6 | input:中 7 | u'\u4e2d' 8 | 9 | 提示: 可以在print時使用 repr 10 | """ 11 | -------------------------------------------------------------------------------- /courses/novice/exercises/week2/1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 將 data 轉換成 [1,2,3,4,5,6,7,8, 9,10, 'A', 11,12,13,14,15] 3 | # note: 不可使用list slice 4 | answer = None 5 | data = [ [1,2,3,4,5], [6,7,8,9,10], [11,12,13,14,15] ] 6 | assert answer == [1,2,3,4,5,6,7,8, 9,10, 'A', 11,12,13,14,15], answer 7 | -------------------------------------------------------------------------------- /courses/novice/exercises/week2/2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 將 data 轉換成一維陣列 3 | # 不可以使用list slice 4 | answer = None 5 | data = [ [1,2,3,4,5], [6,7,8,9,10], [11,12,13, [100,200, 300, 400, ['FOO'] ], 14,15] ] 6 | assert answer == [1,2,3,4,5,6,7,8, 9,10, 'A', 11,12,13, 100, 200, 300, 400, 'FOO', 14,15], answer 7 | -------------------------------------------------------------------------------- /courses/novice/exercises/week2/3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # data 是一個包含整數1到500的list, 寫一個程式把總和算出來 4 | # Note: 不可以使用`sum` function. 5 | answer = 0 6 | data = range(1,501) 7 | assert answer == 125250, answer 8 | -------------------------------------------------------------------------------- /courses/novice/exercises/week2/4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 將變數 data 轉換成'a=1, b=2, c=3, d=4' 3 | answer = None 4 | data = {'a':1, 'b':2, 'c':3, 'd':4} 5 | assert answer == 'a=1, b=2, c=3, d=4', answer 6 | -------------------------------------------------------------------------------- /courses/novice/exercises/week2/5.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 將 data1 與 data2 合併成為一個陣列, 合併規則為 3 | # [ (data1 第一個元素, data2 第一個元素), (data1 第二個元素, data2 第二個元素), .... ] 4 | answer = None 5 | data1 = [1,2,3,4,5] 6 | data2 = ['A', 'B', 'C', 'D', 'E'] 7 | assert answer == [ (1,'A'), (2,'B'), (3,'C'), (4, 'D'),(5,'E') ] 8 | -------------------------------------------------------------------------------- /courses/novice/exercises/week3/1.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # 4 | # 現有兩陣列 A, B,請撰寫ㄧFunction 名叫*uniq_merge*, 功用為能將兩個陣列合併,並去除重複的字串或數字 5 | # 6 | # Input: 兩個一維陣列 7 | # Output: 一個一維陣列 8 | A = ['been', 'for', 'posting', 7, 'looking', 1, 'and', 'this!', 5, 0, 'a', 'Xmonad', 'uses', 'replacement', 'might', 'ratpoison', 'it.', 2, 'Ubuntu', 8, 3, 'Dvorak', 'Thanks', 'for', 6, 'be', 'who', 'here.', 4, "I've", 'typist'] 9 | B = [1, 11, 'typist', 'Dvorak', 'it.', 9, 'be', 'for', 'a', 'uses', 'posting', 'looking', 4, 6, 'this!', 10, 'Xmonad', 'replacement', 13, 'ratpoison', 'who', 8, 0, 'Ubuntu', 'might', 'a', 7, "I've", 'and', 3, 5, 'for', 'been', 'Thanks', 12, 'here.', 2, 'a'] 10 | 11 | def uniq_merge(a,b): 12 | pass 13 | 14 | excepted = ['and', 1, 2, 3, 4, 5, 0, 7, 8, 9, 10, 11, 12, 13, 'Xmonad', 6, 'for', "I've", 'been', 'looking', 'Ubuntu', 'Dvorak', 'might', 'here.', 'it.', 'a', 'posting', 'who', 'uses', 'be', 'this!', 'Thanks', 'typist', 'ratpoison', 'replacement'] 15 | assert excepted == uniq_merge(A,B) 16 | -------------------------------------------------------------------------------- /courses/novice/exercises/week3/2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # 4 | # 延伸1.py, 請撰寫ㄧFunction 名叫*uniq_merge2*, 功用為能將多個一維陣列合併,並去除重複的字串或數字 5 | def uniq_merge2(): 6 | pass 7 | -------------------------------------------------------------------------------- /courses/novice/exercises/week3/3.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # 4 | # 延伸2.py, 請撰寫ㄧFunction 名叫*uniq_merge3*, 功用為能將多個一維List合併,並去除重複的字串或數字 5 | # 6 | # 與第二題不同的是, 你必須在1行內寫完 7 | def uniq_merge3(): 8 | pass # code 寫這 9 | -------------------------------------------------------------------------------- /courses/novice/exercises/week3/4.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # A是一維List, 請撰寫一個function 名叫*get_num_lager_five* 來找出比5大的數字 3 | # 4 | # Input: 一維List, 裡面元素皆為整數 5 | # Output: 一維List, 裡面的元素皆為大於5的整數 6 | def get_num_lager_five(): 7 | pass # code 寫這 8 | -------------------------------------------------------------------------------- /courses/novice/exercises/week3/5.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # 撰寫一個function名為*can_be_div_to_3*判斷一個整數是不是3的倍數, 並且一行內寫完 4 | # 5 | # Input: 整數 6 | # Output: Boolean 7 | def can_be_div_to_3(e): 8 | pass # code 寫這 9 | -------------------------------------------------------------------------------- /courses/novice/exercises/week3/6.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # 想出方法不使用 if..else 重寫ask_it來達成同樣的功能 5 | # 6 | 7 | def answer_yes(name): 8 | print 'YES, ' + name 9 | 10 | def answer_no(name): 11 | print 'NO, ' + name 12 | 13 | ret = raw_input('yes or no?') 14 | 15 | def ask_it(ret): 16 | if ret == 'yes': 17 | answer_yes('My Lord') 18 | elif ret == 'no': 19 | answer_no('man') 20 | 21 | ask_it(ret) 22 | --------------------------------------------------------------------------------