Python 学习成长记(四)---- Python 流程控制
2017-04-19 16:15
351 查看
最近准备重新系统学习一下Python语言,着手研读Python 3.6.1官方教程文档,于是想着不如翻译整理出来 , 希望能帮到一起学习Python的同学们,与大家一起进步,由于水平有限,翻译若有不妥之处,请大家指正 。
本文翻译 Python 官方教程第四章:More Control Flow Tools
除了《Python 学习成长记(三)—- Python 基本用法简介》介绍的while语句, Python也有类似其他语言已知的通用流程控制语句,但有些不太一样。
可以没有或多个elif部分,else部分是可选的。 关键字“elif”是“else if”的缩写,有助于避免过度缩进。 if… elif … elif …语法是替换其他语言中的switch或case语句。
如果您需要修改循环内的迭代顺序(例如复制所选项),建议您先复制一份。 迭代序列不会隐式地复制。 slice使得此功能更加方便:
如果在这个例子中使用
给定的终点不是生成的序列的一部分; 例如range(10)生成10个值,即长度为10的序列。Python还可以让范围从另一个数字开始,或者指定不同的增量(甚至是负的;有时这被称为“步长” ):例如
要迭代序列的索引,可以将range()和len()组合使用,如下:
然而,在大多数情况下,使用enumerate()函数更方便,请参阅循环技术。
如果你打印一个range(),就会发生比较奇怪的事情:
在很多时候,range()返回的对象的行为觉得它是一个list,但实际上它不是。当您遍历它时,它是返回所需序列的连续items的对象,但它并不真正的列表,这样可以节省空间。
如果需要打印这个值得先转成list对象,然后再打印, 如
稍后我们将分析更多的函数,这些函数是返回iterables并以iterables为参数的。
循环语句可能还有一个else子句; 它在循环结束后才执行,而不是由break语句终止后时才执行。 下面是一个搜索素数的循环例子:
(是的,这是正确的代码。仔细看看:else子句属于for循环,而不是if语句。)
当与循环一起使用时,else子句与try语句的else子句相同,而不是if语句:try语句的else子句将在没有异常发生的情况下运行, 循环的else子句在没有发生break的情况下运行 。 有关try语句和异常的更多信息,请参阅处理异常。
continue语句将继续运行循环的下一个迭代:
它通常用于创建最小类:
当你在编写代码时,可以使用pass作为函数或条件体的占位符,从而使你能够在更抽象的层面上思考。 Pass将被忽略:
关键词def用来定义一个新的函数。它后面必须跟随函数名称和形参。函数体从下一行开始,必须缩进。
函数体的第一个语句可以是字符串文字(可选); 这个字符串用来介绍该函数的功能文档。 (有关docstrings的更多信息可以在文档字符串部分中找到。)有些工具使用docstrings自动生成在线或打印的文档,或者让用户交互式浏览代码; 在你写的代码中包含docstrings是一个很好的做法,应该形成一个习惯。
函数的执行过程中引入了可用于函数的局部变量的新符号表,更准确地说,函数中的所有变量赋值将存储在本地符号表中; 而变量引用首先在本地符号表中查找,其次在封闭函数的本地符号表中查找,再次在全局符号表中查找,最后才查找表中的内置名称。因此,全局变量不能被直接赋予函数内的值(除非在全局语句中命名)。
函数调用的实际参数(参数)在被调用函数的局部符号表中被引入;因此,使用call by value传递参数(其值始终是对象引用,而不是对象的值)。 当函数调用另一个函数时,将为该调用创建一个新的本地符号表。
函数定义在当前符号表中引入函数名称。函数名称的值具有由解释器识别为用户定义函数的类型。该值可以分配给另一个名称,然后可以将其用作函数。这是一个通用的重命名机制:
与其他语言相比,由于没有返回值,你可能会觉得该fib不是一个函数,而是一个程序,事实上,即使没有return语句的函数也会返回一个值,尽管这是一个非常无聊的值。 此值称为None(它是一个内置的名称)。 如果写入的值是唯一的值,则写入值None通常被解释器抑制。 如:
编写一个返回Fibonacci数列list的函数很简单,
这个例子像往常一样演示了一些新的Python特性:
return语句返回一个来自函数的值。 返没有表达式参数return None。
result.append(a)调用list对象result方法。 一个方法是一个“属于”一个对象并被命名为obj.methodname的函数,其中obj是
f00d
某一对象(也可能是一个表达式),而methodname是由对象的类型定义的方法的名称。 不同的类型定义不同的方法。 不同类型的方法可能具有相同的名称,而不会引起歧义。 (可以使用类定义自己的对象类型和方法,请参阅Classes)示例中的方法append()是为list对象定义的; 它在list的末尾添加了一个新元素。 在这个例子中,它相当于result = result + [a],但效率更高。
这个函数可以用以下几种方式调用:
只提供强制性的参数:
给出一个可选参数:
甚至给出所有的参数:
此示例还介绍了in关键字。 用来检索序列是否包含某个值。
默认值在定义范围内的函数定义点被使用,因此
结果应该输出5
重要警告:默认值仅能被使用一次。 当默认是可变对象(如list,dictionary或大多数类的实例)时,这将有所不同。 例如,以下函数在后续调用时累加传递给它的参数:
它将会打印
[1]
[1, 2]
[1, 2, 3]
如果您不希望在后续调用之间共享默认值,则可以这样写:
接受一个必需的参数(voltage)和三个可选参数(state,action和type)。 可以通过以下任一方式调用此函数:
但以下所有的调用方式是无效:
在函数调用中,关键字参数必须遵循位置参数。 传递的所有关键字参数必须与函数接受的参数之一匹配(例如,actor不是parrot函数的有效参数),并且它们的顺序并不重要。 这也包括非可选参数(例如parrot(voltage= 1000)也是有效的)。参数不能多次获得赋值。 以下这个失败的例子是由于没有限制参数:
当一个以**name形式的最终形参存在时,它会收到包含所有关键字参数的dictionary(请参阅映射类型 - dict),除了那些与形参对应的关键字参数。 这可以与以* name形式的形参组合, 这些形参可以接收包含超出形参列表的位置参数的元素(将在下一小节中描述)。 (*name必须在**name之前出现。)例如,如果我们定义一个这样的函数:
它可以这样调用
请注意,打印关键字参数的顺序须与函数调用中提供的顺序相匹配。
通常,这些variadic参数将在形参列表中最后出现,因为它们会遍历传递给函数的所有剩余输入参数。 在* args参数之后发生的任何形参都是“仅关键字”参数,这意味着它们只能用作关键字而不是位置参数。
同理,字典可以使用** -运算符来传递关键字参数:
上面的例子使用lambda表达式来返回一个函数。 另一个用途是传递一个小的函数作为参数:
第一行应该是该对象的简短总结。为了简洁起见,它不应该显式地声明对象的名称或类型,因为这些可以通过其他方式使用(除非名称恰好是描述函数操作的动词)。这行应该以大写字母开头,并以句号结束。
如果文档字符串中有多行,则第二行应为空白,将摘要与其余描述区分开。其余行应该是一个或多个段落描述对象的调用约定,其副作用等的。
Python解析器不会在Python中删除多行字符串文字的缩进,因此处理文档的工具必须根据需要删除缩进。这是使用以下约定完成的。字符串第一行之后的第一个非空行确定整个文档字符串的缩进量。 (我们不能使用第一行,因为它通常与字符串的开头引号相邻,因此它的缩进在字符串文字中不明显)。然后从该字符串的所有行的起始处删除与此缩进的“等效”空格。那些没有缩进的行不应该发生,但是如果它们发生的话,所有的空格应该被剥离。应在扩展tabs后(通常为8个空格)来测试空格的等同性。
这是一个多行的docstring的例子:
注释作为字典存储在函数的annotations属性中,对函数的任何其他部分没有影响。 参数注释由参数名后面的冒号定义,后跟一个表达式计算注释的值。 返回注释由‘- >’定义(后跟一个表达式)定义在参数列表和冒号之间。 以下示例具有位置参数,关键字参数和注释的返回值:
对于Python,PEP 8已经成为大多数项目遵循的风格指南;它是一种可读性高和令人着迷的编码风格。每个Python开发人员都应该在某些时候阅读它;这里是为您提取的最重要的一点:
使用4空格缩进,而不是tabs。
4个空格是小缩进之间的一个很好的妥协(允许更大的嵌套深度)和大的缩进(更容易阅读)。Tabs会引起混乱,最好不要了。
一行最好不超过79个字符。
这让用户可以使用小型尺寸的显示器,或者在较大的显示器上可以并排放置多个代码文件。
使用空行来分离函数和类,以及函数中较大的代码块。
如有可能,将注释放在单独一行。
使用docstrings。
在运算符周围,逗号后面使用空格,如:a = f(1, 2) + g(3, 4)。
一致地命名你的类和方法; 惯例是类使用CamelCase,函数和方法使用lower_case_with_underscores。始终使用self作为第一个方法参数的名称(有关类和方法的更多信息,请参阅A First Look at Classes)。
如果你的代码旨在在国际环境中使用,请勿使用花式编码。在任何情况下,Python的默认值,UTF-8或甚至纯ASCII效果最好。
同样地,由于不同国家的人可能会言会读取或维护代码,请勿在标识符中使用非ASCII字符。
本文翻译 Python 官方教程第四章:More Control Flow Tools
除了《Python 学习成长记(三)—- Python 基本用法简介》介绍的while语句, Python也有类似其他语言已知的通用流程控制语句,但有些不太一样。
4.1 if 语句
也许最着名的是if语句。 例如:>>> x = int(input("Please enter an integer: ")) Please enter an integer: 42 >>> if x < 0: ... x = 0 ... print('Negative changed to zero') ... elif x == 0: ... print('Zero') ... elif x == 1: ... print('Single') ... else: ... print('More') ... More
可以没有或多个elif部分,else部分是可选的。 关键字“elif”是“else if”的缩写,有助于避免过度缩进。 if… elif … elif …语法是替换其他语言中的switch或case语句。
4.2 for循环语句
Python中的for语句可能与C或Pascal中的for语句使用有一点点不同。 它不是总是用迭代数字的算术过程(如Pascal),或者给予用户定义迭代步骤和停止条件(如C语言),Python的for语句可以迭代任何序列的item(List or String),按序列中顺序来执行。 例如:>>> # Measure some strings: ... words = ['cat', 'window', 'defenestrate'] >>> for w in words: ... print(w, len(w)) ... cat 3 window 6 defenestrate 12
如果您需要修改循环内的迭代顺序(例如复制所选项),建议您先复制一份。 迭代序列不会隐式地复制。 slice使得此功能更加方便:
>>> for w in words[:]: # Loop over a slice copy of the entire list. ... if len(w) > 6: ... words.insert(0, w) ... >>> words ['defenestrate', 'cat', 'window', 'defenestrate']
如果在这个例子中使用
for w in words:, 那么它将无限循环地往words这个list中插入defenestrate
4.3 range()函数
如果你确实需要迭代一个数字序列,内置的函数range()就派上用场了:>>> for i in range(5): ... print(i) ... 0 1 2 3 4
给定的终点不是生成的序列的一部分; 例如range(10)生成10个值,即长度为10的序列。Python还可以让范围从另一个数字开始,或者指定不同的增量(甚至是负的;有时这被称为“步长” ):例如
range(5, 10) 5 through 9 range(0, 10, 3) 0, 3, 6, 9 range(-10, -100, -30) -10, -40, -70
要迭代序列的索引,可以将range()和len()组合使用,如下:
>>> a = ['Mary', 'had', 'a', 'little', 'lamb'] >>> for i in range(len(a)): ... print(i, a[i]) ... 0 Mary 1 had 2 a 3 little 4 lamb
然而,在大多数情况下,使用enumerate()函数更方便,请参阅循环技术。
如果你打印一个range(),就会发生比较奇怪的事情:
>>> print(range(10)) range(0, 10)
在很多时候,range()返回的对象的行为觉得它是一个list,但实际上它不是。当您遍历它时,它是返回所需序列的连续items的对象,但它并不真正的列表,这样可以节省空间。
如果需要打印这个值得先转成list对象,然后再打印, 如
>>> list(range(5)) [0, 1, 2, 3, 4]
稍后我们将分析更多的函数,这些函数是返回iterables并以iterables为参数的。
4.4 break和continue语句,及其它循环的语法
break语句就像在C语言使用一样,跳出最小的for或while循环。循环语句可能还有一个else子句; 它在循环结束后才执行,而不是由break语句终止后时才执行。 下面是一个搜索素数的循环例子:
>>> for n in range(2, 10): ... for x in range(2, n): ... if n % x == 0: ... print(n, 'equals', x, '*', n//x) ... break ... else: ... # loop fell through without finding a factor ... print(n, 'is a prime number') ... 2 is a prime number 3 is a prime number 4 equals 2 * 2 5 is a prime number 6 equals 2 * 3 7 is a prime number 8 equals 2 * 4 9 equals 3 * 3
(是的,这是正确的代码。仔细看看:else子句属于for循环,而不是if语句。)
当与循环一起使用时,else子句与try语句的else子句相同,而不是if语句:try语句的else子句将在没有异常发生的情况下运行, 循环的else子句在没有发生break的情况下运行 。 有关try语句和异常的更多信息,请参阅处理异常。
continue语句将继续运行循环的下一个迭代:
>>> for num in range(2, 10): ... if num % 2 == 0: ... print("Found an even number", num) ... continue ... print("Found a number", num) Found an even number 2 Found a number 3 Found an even number 4 Found a number 5 Found an even number 6 Found a number 7 Found an even number 8 Found a number 9
4.5 pass 语句
Pass语句不做任何事情。 当在语法上需要但程序不需要任何动作时,可以使用它。 例如:>>> while True: ... pass # Busy-wait for keyboard interrupt (Ctrl+C) ...
它通常用于创建最小类:
>>> class MyEmptyClass: ... pass ...
当你在编写代码时,可以使用pass作为函数或条件体的占位符,从而使你能够在更抽象的层面上思考。 Pass将被忽略:
>>> def initlog(*args): ... pass # Remember to implement this! ...
4.6 这里写链接内容定义函数
我们可以创建一个函数来实现带任意边界的Fibonacci系列:>>> def fib(n): # write Fibonacci series up to n ... """Print a Fibonacci series up to n.""" ... a, b = 0, 1 ... while a < n: ... print(a, end=' ') ... a, b = b, a+b ... print() ... >>> # Now call the function we just defined: ... fib(2000) 0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
关键词def用来定义一个新的函数。它后面必须跟随函数名称和形参。函数体从下一行开始,必须缩进。
函数体的第一个语句可以是字符串文字(可选); 这个字符串用来介绍该函数的功能文档。 (有关docstrings的更多信息可以在文档字符串部分中找到。)有些工具使用docstrings自动生成在线或打印的文档,或者让用户交互式浏览代码; 在你写的代码中包含docstrings是一个很好的做法,应该形成一个习惯。
函数的执行过程中引入了可用于函数的局部变量的新符号表,更准确地说,函数中的所有变量赋值将存储在本地符号表中; 而变量引用首先在本地符号表中查找,其次在封闭函数的本地符号表中查找,再次在全局符号表中查找,最后才查找表中的内置名称。因此,全局变量不能被直接赋予函数内的值(除非在全局语句中命名)。
函数调用的实际参数(参数)在被调用函数的局部符号表中被引入;因此,使用call by value传递参数(其值始终是对象引用,而不是对象的值)。 当函数调用另一个函数时,将为该调用创建一个新的本地符号表。
函数定义在当前符号表中引入函数名称。函数名称的值具有由解释器识别为用户定义函数的类型。该值可以分配给另一个名称,然后可以将其用作函数。这是一个通用的重命名机制:
>>> fib <function fib at 10042ed0> >>> f = fib >>> f(100) 0 1 1 2 3 5 8 13 21 34 55 89
与其他语言相比,由于没有返回值,你可能会觉得该fib不是一个函数,而是一个程序,事实上,即使没有return语句的函数也会返回一个值,尽管这是一个非常无聊的值。 此值称为None(它是一个内置的名称)。 如果写入的值是唯一的值,则写入值None通常被解释器抑制。 如:
>>> fib(0) >>> print(fib(0)) None
编写一个返回Fibonacci数列list的函数很简单,
>>> def fib2(n): # return Fibonacci series up to n ... """Return a list containing the Fibonacci series up to n.""" ... result = [] ... a, b = 0, 1 ... while a < n: ... result.append(a) # see below ... a, b = b, a+b ... return result ... >>> f100 = fib2(100) # call it >>> f100 # write the result [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
这个例子像往常一样演示了一些新的Python特性:
return语句返回一个来自函数的值。 返没有表达式参数return None。
result.append(a)调用list对象result方法。 一个方法是一个“属于”一个对象并被命名为obj.methodname的函数,其中obj是
f00d
某一对象(也可能是一个表达式),而methodname是由对象的类型定义的方法的名称。 不同的类型定义不同的方法。 不同类型的方法可能具有相同的名称,而不会引起歧义。 (可以使用类定义自己的对象类型和方法,请参阅Classes)示例中的方法append()是为list对象定义的; 它在list的末尾添加了一个新元素。 在这个例子中,它相当于result = result + [a],但效率更高。
4.7 更多关于定义功能
也可以使用可变数量的参数来定义函数。 有三种形式可以组合。4.7.1 默认参数值
最有用的形式是为一个或多个参数指定默认值。 这样,在函数中,就可以使用比定义允许的参数的个数少。 例如:def ask_ok(prompt, retries=4, reminder='Please try again!'): while True: ok = input(prompt) if ok in ('y', 'ye', 'yes'): return True if ok in ('n', 'no', 'nop', 'nope'): return False retries = retries - 1 if retries < 0: raise ValueError('invalid user response') print(reminder)
这个函数可以用以下几种方式调用:
只提供强制性的参数:
ask_ok('Do you really want to quit?')
给出一个可选参数:
ask_ok('OK to overwrite the file?', 2)
甚至给出所有的参数:
ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')
此示例还介绍了in关键字。 用来检索序列是否包含某个值。
默认值在定义范围内的函数定义点被使用,因此
>>> i = 5 >>> def f(arg=i): print(arg) >>> i= 6 >>> f()
结果应该输出5
重要警告:默认值仅能被使用一次。 当默认是可变对象(如list,dictionary或大多数类的实例)时,这将有所不同。 例如,以下函数在后续调用时累加传递给它的参数:
def f(a, L=[]): L.append(a) return L print(f(1)) print(f(2)) print(f(3))
它将会打印
[1]
[1, 2]
[1, 2, 3]
如果您不希望在后续调用之间共享默认值,则可以这样写:
def f(a, L=None): if L is None: L = [] L.append(a) return L
4.7.2 关键字参数
函数也可以使用kwarg = value格式的关键字参数来调用。 例如:def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'): print("-- This parrot wouldn't", action, end=' ') print("if you put", voltage, "volts through it.") print("-- Lovely plumage, the", type) print("-- It's", state, "!")
接受一个必需的参数(voltage)和三个可选参数(state,action和type)。 可以通过以下任一方式调用此函数:
parrot(1000) # 1 positional argument parrot(voltage=1000) # 1 keyword argument parrot(voltage=1000000, action='VOOOOOM') # 2 keyword arguments parrot(action='VOOOOOM', voltage=1000000) # 2 keyword arguments parrot('a million', 'bereft of life', 'jump') # 3 positional arguments parrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
但以下所有的调用方式是无效:
parrot() # required argument missing parrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argument parrot(110, voltage=220) # duplicate value for the same argument parrot(actor='John Cleese') # unknown keyword argument
在函数调用中,关键字参数必须遵循位置参数。 传递的所有关键字参数必须与函数接受的参数之一匹配(例如,actor不是parrot函数的有效参数),并且它们的顺序并不重要。 这也包括非可选参数(例如parrot(voltage= 1000)也是有效的)。参数不能多次获得赋值。 以下这个失败的例子是由于没有限制参数:
>>> def function(a): ... pass ... >>> function(0, a=0) Traceback (most recent call last): File "<stdin>", line 1, in ? TypeError: function() got multiple values for keyword argument 'a'
当一个以**name形式的最终形参存在时,它会收到包含所有关键字参数的dictionary(请参阅映射类型 - dict),除了那些与形参对应的关键字参数。 这可以与以* name形式的形参组合, 这些形参可以接收包含超出形参列表的位置参数的元素(将在下一小节中描述)。 (*name必须在**name之前出现。)例如,如果我们定义一个这样的函数:
def cheeseshop(kind, *arguments, **keywords): print("-- Do you have any", kind, "?") print("-- I'm sorry, we're all out of", kind) for arg in arguments: print(arg) print("-" * 40) for kw in keywords: print(kw, ":", keywords[kw])
它可以这样调用
>>> cheeseshop("Limburger", "It's very runny, sir.", "It's really very, VERY runny, sir.", shopkeeper="Michael Palin", client="John Cleese", sketch="Cheese Shop Sketch") -- Do you have any Limburger ? -- I'm sorry, we're all out of Limburger It's very runny, sir. It's really very, VERY runny, sir. ---------------------------------------- shopkeeper : Michael Palin client : John Cleese sketch : Cheese Shop Sketch >>>
请注意,打印关键字参数的顺序须与函数调用中提供的顺序相匹配。
4.7.3 任意参数列表
最后,最常用的选项是指定可以使用任意数量的参数调用函数。 这些参数将被包装在一个tuple元组中(参见元组和序列)。 在可变数量的参数之前,可能会出现零个或多个正常def write_multiple_items(file, separator, *args): file.write(separator.join(args))
通常,这些variadic参数将在形参列表中最后出现,因为它们会遍历传递给函数的所有剩余输入参数。 在* args参数之后发生的任何形参都是“仅关键字”参数,这意味着它们只能用作关键字而不是位置参数。
>>> def concat(*args, sep="/"): ... return sep.join(args) ... >>> concat("earth", "mars", "venus") 'earth/mars/venus' >>> concat("earth", "mars", "venus", sep=".") 'earth.mars.venus'
4.7.4 Unpacking Argument Lists
当参数已经在list或tuple中,但是需要被解压缩给需要单独位置参数的函数调用时,会发生相反的情况。 例如,内置函数range()需要单独的起始和停止参数。 如果它们不是单独可用,需要使用*操作符来解压list或者tupleq外的参数给函数调用:>>> list(range(3, 6)) # normal call with separate arguments [3, 4, 5] >>> args = [3, 6] >>> list(range(*args)) # call with arguments unpacked from a list [3, 4, 5]
同理,字典可以使用** -运算符来传递关键字参数:
>>> def parrot(voltage, state='a stiff', action='voom'): ... print("-- This parrot wouldn't", action, end=' ') ... print("if you put", voltage, "volts through it.", end=' ') ... print("E's", state, "!") ... >>> d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"} >>> parrot(**d) -- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !
4.7.5 Lambda 表达式
可以使用lambda关键字创建小型匿名函数。 此函数返回其两个参数lambda a,b的和a + b。 Lambda函数可以在需要函数对象的地方使用。 它们在语法上仅限于单个表达式。 语义上,它们只是正常功能定义的语法糖。 像嵌套函数定义一样,lambda函数可以引用包含范围的变量:>>> def make_incrementor(n): ... return lambda x: x + n ... >>> f = make_incrementor(42) >>> f(0) 42 >>> f(1) 43
上面的例子使用lambda表达式来返回一个函数。 另一个用途是传递一个小的函数作为参数:
>>> pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')] >>> pairs.sort(key=lambda pair: pair[1]) >>> pairs [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]
4.7.6 文档字符串
以下是关于文档字符串的内容和格式的一些约定。第一行应该是该对象的简短总结。为了简洁起见,它不应该显式地声明对象的名称或类型,因为这些可以通过其他方式使用(除非名称恰好是描述函数操作的动词)。这行应该以大写字母开头,并以句号结束。
如果文档字符串中有多行,则第二行应为空白,将摘要与其余描述区分开。其余行应该是一个或多个段落描述对象的调用约定,其副作用等的。
Python解析器不会在Python中删除多行字符串文字的缩进,因此处理文档的工具必须根据需要删除缩进。这是使用以下约定完成的。字符串第一行之后的第一个非空行确定整个文档字符串的缩进量。 (我们不能使用第一行,因为它通常与字符串的开头引号相邻,因此它的缩进在字符串文字中不明显)。然后从该字符串的所有行的起始处删除与此缩进的“等效”空格。那些没有缩进的行不应该发生,但是如果它们发生的话,所有的空格应该被剥离。应在扩展tabs后(通常为8个空格)来测试空格的等同性。
这是一个多行的docstring的例子:
>>> def my_function(): ... """Do nothing, but document it. ... ... No, really, it doesn't do anything. ... """ ... pass ... >>> print(my_function.__doc__) Do nothing, but document it. No, really, it doesn't do anything.
4.7.7 函数注释
函数注释是完全可选metadata信息,这些信息是关于用户定义函数的使用类型(有关详细信息,请参阅PEP 484)。注释作为字典存储在函数的annotations属性中,对函数的任何其他部分没有影响。 参数注释由参数名后面的冒号定义,后跟一个表达式计算注释的值。 返回注释由‘- >’定义(后跟一个表达式)定义在参数列表和冒号之间。 以下示例具有位置参数,关键字参数和注释的返回值:
>>> def f(ham: str, eggs: str = 'eggs') -> str: ... print("Annotations:", f.__annotations__) ... print("Arguments:", ham, eggs) ... return ham + ' and ' + eggs ... >>> f('spam') Annotations: {'ham': <class 'str'>, 'return': <class 'str'>, 'eggs': <class 'str'>} Arguments: spam eggs 'spam and eggs'
4.8 Intermezzo: 编码风格
如果你将要编写更长更复杂的Python,那么就有必要谈谈编码风格了。大多数语言可以写成(或更简洁,格式化)的不同风格; 可读性更高。让别人轻松阅读你的代码永远是一个好主意,采用一个很好的编码风格是有有很大的帮助的。对于Python,PEP 8已经成为大多数项目遵循的风格指南;它是一种可读性高和令人着迷的编码风格。每个Python开发人员都应该在某些时候阅读它;这里是为您提取的最重要的一点:
使用4空格缩进,而不是tabs。
4个空格是小缩进之间的一个很好的妥协(允许更大的嵌套深度)和大的缩进(更容易阅读)。Tabs会引起混乱,最好不要了。
一行最好不超过79个字符。
这让用户可以使用小型尺寸的显示器,或者在较大的显示器上可以并排放置多个代码文件。
使用空行来分离函数和类,以及函数中较大的代码块。
如有可能,将注释放在单独一行。
使用docstrings。
在运算符周围,逗号后面使用空格,如:a = f(1, 2) + g(3, 4)。
一致地命名你的类和方法; 惯例是类使用CamelCase,函数和方法使用lower_case_with_underscores。始终使用self作为第一个方法参数的名称(有关类和方法的更多信息,请参阅A First Look at Classes)。
如果你的代码旨在在国际环境中使用,请勿使用花式编码。在任何情况下,Python的默认值,UTF-8或甚至纯ASCII效果最好。
同样地,由于不同国家的人可能会言会读取或维护代码,请勿在标识符中使用非ASCII字符。
相关文章推荐
- 小Y的Python学习日志--流程控制(逻辑符)
- python学习笔记二:流程控制
- python 学习之流程控制if for while 及print 格式控制
- python学习笔记一 介绍、基本语法、流程控制
- python学习4-流程控制-逻辑运算符
- python学习笔记五——流程控制
- python学习 流程控制语句详解
- python学习6-流程控制
- Python3 学习手册(二) 流程控制语句
- python学习8-流程控制-while
- python 学习笔记-山寨携程(列表,字符串,字典和流程控制总结)
- python学习 流程控制语句详解
- Python学习(七) 流程控制if语句
- Python学习 第4天 基本语法-变量、数据类型、运算符、流程控制
- Python 学习笔记 (2)—— 流程控制
- Python学习(二):入门篇:python中流程控制与函数编写
- python学习笔记3—流程控制if、for、while
- python学习 流程控制语句
- python学习6-流程控制-for循环
- python学习4-流程控制-分支结构