======Control Structures====== //Chapter 3 notes// ---- ====Control Structures==== * 控制程序执行流程的代码 ===Conditionals=== * 基于逻辑表达式选择不同的执行方式 * if / else ==indentation and conditionals== * python 中所有具有相同缩进的代码被视作同一个 block 下的代码 * 缩进也可以嵌套 * Loops * Functions * Exceptions ===scope=== * scope 指在程序执行中使变量可见的区域 * 编译性语言和解释性语言有所不同 * scope 通过 control structure 来体现 * conditional 不能保证自身运行,因此其内部的变量不能对外部可见 * function 内部的变量对外部不可见 ==scope in python== * python 中的变量 scope 从变量创建的一刻开始 * 该变量需要到下一行才能使用(不能创建中使用自身) ==if / else in python== * 条件语句下的 block 会接一个 '':'' ===condition & boolean operators=== * 可以通过 boolean 表达式来制定条件 * boolean 表达式可以接受返回 boolean 的 function * boolean 运算符可以用于连接多个表达式 ==使用 member op 作为条件表达式== 可以通过 ''in'' 成员查询条件是否属于某个条件集合: club_members = ["John", "Jenny", "Jason", "Jane"] my_name = "Jenny" if my_name in club_members: print("Welcome back!") ''in'' 关键字还可以用于匹配字符串,比如: mystery_string = "zizazzle" if "zzz" in mystery_string = "zizazzle": do sth.... ==使用 function 作为条件表达式== #isdigit() is an member function of string that used as the condition myNumericString = "12345" if myNumericString.isdigit(): prtin("something") ==scope 与 condition== * 条件语句不运行的前提下,其 block 下的 scope 是不存在的。因此所有在该 scope 内部的变量都不存在。 * 推荐在条件语句外部创建 scope (minimun level) ====Loops==== * Loop: A programming control structure that executes a segment of code multiple times. * For loops: A loop control structure that runs a block of code a **predetermined number of times.** * Foreach: 自动循环容器中的所有内容(而不用手动指定循环次数) * While loops: A single execution of a repeated task or** block of code**. * do while: run at least once, then check the condition ===For loop=== ==For Loops in Python== 基本写法: for i in range(1, 11): print(i) ''range'' 是左闭右开区间 $[1,11)$。''range()'' 函数的几种初始化方法: #0 - 9, implicitly range(10) #0 - 9, explicitly range (0 , 10) #0, 2, 4, 6, 8 range(0, 10, 2) #count down(reverse) 10 - 1 range(10, 1, -1) ==Primer on Indices== * 循环适用于长得像 list 一样的主体k * 循环,index 的起点是 ''0'' ==for each loop== for each loop 与 for loop 类似。但相比 for loop,for each 使用变量(list)来作为范围,for each loop 会循环 list 中所有的元素。比如: listOfNumbers = [1,2,3,4,5] for i in listOfNumbers: sum += i 这个等同于如下的 for loop: for i in range(0, len(listOfNumbers)): sum += i python 中,string 也可以作为范围变量;for each 访问的是 string 中的每一个字母: mystring = "abcde" for char in mystring: do sth ===While Loop=== While Loop 适用于我们不清楚循环要进行多少次的情况下。 ==python 的随机数== import random # Returns a random integer greater than or equal to min and less than or equal to max. random.randint(min, max) ==nested loop== 使用 nested loop 统计 list string 中有多少词: * 使用空格作为词数的技术 * 在最后加上整个 list string 的长度补足未计数的部分 list_of_strings = ["This is the 1st string", "This is the 2nd string", "This is the 3rd string", "This is the 4th string", "This is the 5tj string" ] space_count = 0 for current_string in list_of_strings: for curr_char in current_string: if curr_char == " ": space_count += 1 word_counts = space_count + len(list_of_strings) print(word_counts) ===相关概念=== ==重要的 loop 关键字== * ''continue'':跳过当前循环中迭代剩下的内容,跳到下一个迭代 * ''pass'':使用 loop,但什么都不做(空语句) * ''break'':跳出所有的循环 ==scope & loop== * loop 中创建的变量会在下一次迭代中被重新初始化。如果不希望被重置,把变量放到循环外部。 ====Functions==== * **Function**: A segment of code that performs a specific task, sometimes taking some input and sometimes returning some output. ==什么是 call 和 definitaion== * **Function Call**: A **place** where a **function is actually used** in some code. *** Function Definition**: A segment of code that creates a function, including its name, parameters, and code, to be used by other portions of a program. * **Function Header**: The name and list of parameters a function expects, provided as reference to the rest of the program to use when calling the function. * **name** * **Parameter**: A variable for which a function expects to receive a value when called, whose scope is the function’s own execution. *** Function Body**: The code that a function runs when called. * **Return Statemen**t: The line of code that defines what output will be sent back at the end of a function. ==call 的过程== * 给 function paramater 使用的**值**被称为 Arguments。可以将 parameter 视作 variable, Arguments 视作具体值。 * 需要注意的三点: * how to call * what input will be given * what output to expect(某些 call 不会返回值) ===function in python=== ==定义 function== #defination def printYen(): print("$", end='') # call printYen() python 中必须先定义函数再使用。 ==parameter & returns == # return def returnYen(): return "Y" # using parameter def returnYenAmount(amount): return "Y" + str(amount) print(returnYenAmount(5)) return 会直接终止当前 function body 的继续运行 ==注意事项== * **not** to use the **same variable names** in your parameter list that you use in the rest of your program * always make sure to check full_results.txt ==常见错误== * Parameter Mismatch:argument 和 parameter 的数量不同,或是参数不匹配。 * Scope Error: * 函数内部的变量的 scope 只处于函数内部。 ==None== * 如果函数不返回任何值,那么返回 None * 需要确保每个 conditional 中都有正确的 return (包括 nested conditional) * 循环结束时可能没有成功匹配条件,因此需要在 loop 结束后手动 return ==keyword parameters== keyword prarameter 指函数中的自带的,用于实现某种特殊功能的**可选**参数(可忽略)。比如 ''print()'': #sep is the character between string A and string B #end is the character added at the end of the printed string #output will be A#B! # by default, sep = space, end = newline print("A", "B", sep = "#", end = "!") keyword parameter 处于所有函数 parameter 的后方,可以自定义;功能类似 C++ 的函数默认值。比如: #currency has default value USD def currencyAmount(amount, currency = "USD") #when calling, currency can be changed by signing an parameter to it currencyAmount(5, currency = "GBP") ====Exception Handling==== * Exception Handling 针对的是**某些可以预期**的问题。这些问题通常不重要,但有时会影响到用户的使用体验。Exception Handling 可以尽可能的使用户避免这些问题。 ==catching” Errors== * 如果 error 没有被捕获(uncaught error),很可能导致程序崩溃 * 对 error 进行捕获 (catching error) 可以避免程序的崩溃 catching error 与通常避免错误的处理方式不同。通常的处理的方式是**阻止错误**的发生;比如不允许除零的行为,来保证程序的正常运行。而 catching error 是对 error 做处理,**保证遭遇错误的时候程序依然能够正常运行**:比如当用户进行除零的行为时,catching error 首先告诉电脑**不要 crash**,其次再通过电脑告知用户除零这种操作是不允许的。 ==Catch Error 的优势== - 对于独立的 function, catching error 允许我们首先考虑 code 本身的功能,在之后再去考虑可能产生什么样的 error * catching error 的方式可以允许程序执行一部分直到错误的出现 - 相比把所有错误检测的条件语句放到程序之前,catch error 将所有 error 的处理放到最后,使程序更易读 - catching error 可以在遭遇**未知错误**的时候阻止程序 crash ===Try-Catch-Finally=== * The **Try** statement marks a block of code to attempt, but in which we anticipate an error might arise. * The **Catch** statement names the errors to anticipate, and marks a block of code to run if an anticipated error arises. (Python often refers to this as the **Except** block as well.) * The **Finally** statement marks a block of code to run after the above two blocks no matter what. Try block 中的代码是试错用的, catch 是处理 error 用的 ,Final 中的代码是之前两步完成以后一定会运行的代码(应该放一些比较稳当的代码) ===Try and Except=== 在 python 中, try-catch 以 ''try'' - ''except'' 关键字的形式存在。比如下列的例子: try: print("Converting myString to int....") myInt = int(myString) print(myInt) except: pass print(done) 需要注意的是,如果 try block 中有任意错误出现,那么代码会直接跳转到之后的 except block 中;try block 之后的语句都不会执行。相反,如果 try block 中的语句没有出现错误,那么 except block 永远不会执行。 ==指定 except block 中的内容== execpt block 中可以指定对错误内容的反馈(log),比如: try: print("Converting myString to int....") myInt = int(myString) print(myInt) except: print("Can't convert an non-number string to int") ==指定需要捕获的 error== python 中允许我们对指定类型的 error 进行捕获,比如: try: print(1 / 0) print("No error occurred!") except ZeroDivisionError: print("An error occurred!") print("Done!") 这里的 ''print(1/0)'' 是 ''ZeroDivisionError'' 的错误类型,因此 ''except'' block 会成功匹配该错误,并执行该错误下的语句,这里是 ''print("An error occurred!")''。 \\ \\ 但需要注意的是,这种情况下,python 只能捕获 except block 中指定的错误类型。如果出现了别的类型的错误,python 会: - 按通常一样,跳转到 except block - 寻找是否存在与该错误类型对应的 block - 如果没有找到,那么该程序会 crash ==使用变量存储错误信息== 如果我们希望看到一些额外的,关于错误如何抛出的信息,我们可以使用 ''as'' 关键字来存储该信息。写法如下: try: print(1 / 0) except ZeroDivisionError as error: print(error) # variable error stores error info from ZeroDivisionError print("Done!") 此处的 ''error'' 变量可以为任何名字,存储的是 ''ZeroDivisionError'' 带来的信息 ''division by zero''。因此,打印结果为: division by zero Done! ==同时处理多种 error== python 提供了同时处理多种 error 的机制: try: print("String" + 1) print(1 / 0) except ZeroDivisionError: print("A ZeroDivisionError occurred!") except TypeError: print("A TypeError occurred!") print("Done!") 可以注意到, ''print("String" + 1)'' 会导致 ''TypeError''. 当该错误出现时,python 会跳转到 except block 中,以**从上到下**的顺序寻找与该错误类型匹配的 except block。我们的程序中有对应 ''TypeError'' 的处理,因此会打印: A TypeError occurred! Done! 需要注意的是,即便同时存在多种类型的错误,只要成功捕获了一个错误,python 就会执行对应的 except block 中的内容,以及 except block 之后的内容了。即便是 try 中还存在着其他类型的错误,python 也不会在进行执行,比如: try: print("String" + 1) myInt = int("This is string") print(1 / 0) except TypeError: print("A TypeError occurred!") except ZeroDivisionError: print("A ZeroDivisionError occurred!") print("Done!") 这里的 ''myInt = int("This is string")'' 是 ''ValueError'' 类型的错误。按道理来说,由于我们没有提供对应的错误处理,程序应该 crash 掉。但实际上,在其执行之前已经出现了 ''TypeError'' 类型的错误,因此该行代码以及其之后的,在 try block 中的内容都不会执行。因此打印结果与之前的例子一样。\\ \\ 如果需要对**其他剩余的错误**做一个总的处理,可以使用关键字 ''Exception'',比如 try: myInt = int("This is string") print("String" + 1) print(1 / 0) except TypeError as error: print(error) except ZeroDivisionError as error: print(error) except Exception as error: print(error) print("Done!") 如果不指定具体打印内容,python 会自动根据具体的错误类型信息将错误打印出来: Invalid literal for int() with base 10: 'This is string' Done! ===Else and Finally=== ==else 关键字== ''else'' 关键字是 python 特有的一个机制。当所有其他 except block 中的内容都没有执行的时候(也就是 try block 中程序无错运行完毕的时候),python 会跳转到 else block 下的语句运行,比如: mystery_value = 9 try: print( 10 / mystery_value) except ZeroDivisionError: print("Can't divide by zero") except Exception: print("Not possible") else: print("No error found!") 将打印: 1.1111111111111112 No error found! else 关键字可能看起来有些多余。但实际上,因为这个关键字属于 except block 的一部分,而只有当所有 expect block 都没有执行,也就是没有错误被捕获的时候,else block 才会运行。因此,当 else block 中的语句被执行时,我们就可以百分之百的确认之前 try block 里的代码是没有(非逻辑)错误的。 ==else 的重要应用:读取文件== 该应用由如下程序所示: try: #open file in read only mode input_file = open("Fake.txt", mode = "r") except IOError as error: print("An input error occurred!") else: for line in input_file: print lines input_file.close() 该应用中,如果在打开 ''Fake.txt'' 的过程中出现了任何错误,都会被 python 捕获。如果打开正确,则会执行剩余的逐行读取操作(else block 中的部分)。 ==Finally 关键字== 无论 try block 中有没有内容被捕获,Finally block 中内容都会运行: try: #open file in read only mode input_file = open("Fake.txt", mode = "r") except IOError as error: print("An input error occurred!") else: for line in input_file: print lines finally: input_file.close() 这里的 ''input_file.close()'' 一定会被执行。 **为什么不在 try block 后面直接加无论如何都想要运行的代码?** \\ \\ finally 可以保证即便是 try block 中**出现无法处理的错误**(Uncaught Errors)的情况下,也能继续运行 finally block 内的语句。如果直接在 try block 后面添加语句,当出现 Uncaught Errors 时,程序会直接 crash,因此后面的语句也没有机会执行了。 ==使用嵌套的 try block 处理不同的错误== 有如下代码: try: #Open InputFile.txt in read-only mode input_file = open("FakeFile.txt", mode = "r") try: #For each line in the file for line in input_file: #Print the line print(int(line)) #Catch a ValueError except ValueError as error: print("A value error occurred!") else: print("No errors occurred converting the file!") finally: #Close the file input_file.close() #Catch an IOError except IOError as error: print("An error occurred reading the file!") 这段代码中,我们的本意是先验证文件是否能正常打开,再验证文件的内容是否能正确的从 string 转化为 int。对此,我们可以使用嵌套的 try block 结构来处理。可以看到,外部的 try block 处理的是 IOError,而内部的 try block 处理的是 ValueError。几点需要注意的是: * 当外部 try block 捕获匹配的内容时,会直接跳过其之后的内容到对应的**同级** except block 中。以本例为例子中,外部的 try block 并没有做 finally block 的处理。如果外部 try block 遇到 Uncaught Errors 时,内部的 finally block 中的语句时无法打印的。 * 当内部的 try block 捕获错误时,其错误匹配按**由内而外**的顺序来搜寻。也就是: * 优先查找同级 except block 中有没有匹配的错误处理 * 如果没有,回到上级 try block 对应的 except block 中查找 ==return 与 try block 的配合使用== ''return'' 可以终止函数的运行并返回结果。我们可以将这个功能放置在 except block 中来达到终止函数的运行并返回错误信息的效果: def return_file_text(filename): try: file = open(filename) except: return "Error opening file!" file_text = file.read() return file_text ===Error Handling and Control Structures=== ==Error Handling and For Loops== 如果 loop 出现问题就希望结束 loop,那么应该把 try block 包含整个 loop: try: #For each line in the file for line in input_file: #Print the line print(int(line)) #Catch a ValueError except ValueError as error: print("A value error occurred!") 如果希望对单次的 iteration 进行错误捕获,则应该把 try block 放到 loop 中: #For each line in the file for line in input_file: try: #Print the line print(int(line)) #Catch a ValueError except ValueError as error: print("A value error occurred!") 这样的结构只会在出现错误时打断当前的迭代,loop 还会继续执行剩余的部分。 可以在 except block 中使用 break 语句强制结束循环 ==Error Handling and Functions== * 如果 function 中出现错误,那么会首先查找 function 内部是否有 except block * 如果没有,会跳转到外部 function 被调用的位置,查看该位置是否处于 try block 内部。如果处于,则查找是否存在对应的 except block。