Home >Backend Development >Python Tutorial >Detailed introduction to flow control statements in Python
In addition to the while statement just introduced, Python also borrowed other flow control statements from other languages and made corresponding changes. Detailed introduction to flow control statements in Python
if
StatementsPerhaps the most well-known statement is if
statement. For example:
x = int(input("Please enter an integer: "))if x < 0: x = 0print('Negative changed to zero')elif x == 0:print('Zero')elif x == 1:print('Single')else:print('More')
There can be zero or more elif
clauses, and the else
clause is optional. The keyword elif
is an intermittent form of else if
, which can avoid excessive indentation. The if ... elif ... elif ...
sequence is a replacement for the switch
or case
statements in other languages.
for
StatementsThe for
statement in Python is slightly different from the for
statement in C or Pacsal. Python does not use the method of iterating arithmetic sequence numbers (in Pascal) to implement loops, nor does it use the method of defining the number of iteration steps and stopping conditions like C language to implement loops. Python's for
The statement iterates over the items of any sequence (list or string) in the order in which they appear in the sequence. For example (no other meaning):
# Measure some strings:words = ['cat', 'window', 'defenestrate']for w in words:print(w, len(w))
If you need to modify the sequence being traversed within the loop (such as copying the selected item), it is recommended to copy the sequence first. No backups are implicitly created when traversing the sequence. The slicing statement is particularly convenient for copying sequences:
for w in words[:]: # Loop over a slice copy of the entire list.if len(w) > 6: words.insert(0, w) words
Using for w in words:O
, the instance will try to create an infinite list and continuously insert stringsdefenestrate
.
range()
FunctionIf you really need to iterate over a sequence of numbers, the built-in function range()
can be used use. This function generates an arithmetic sequence:
>>> for i in range(5): ... print(i) ...01234
end
The parameters will not be included in the generated sequence; range(10)
generates 10 value, the legal index length of a sequence item is 10. You can start the range at another number, or specify a different increment (even a negative number; sometimes the increment is called a 'step'):
range(5, 10) 5 through 9range(0, 10, 3) 0, 3, 6, 9range(-10, -100, -30) -10, -40, -70
Need to pair the sequence When iterating over the index, you can combine the range()
and len()
functions as follows:
>>> a = ['Mary', 'had', 'a', 'little', 'lamb']>>> for i in range(len(a)): ... print(i, a[i]) ...0 Mary1 had2 a3 little4 lamb
However, in most cases In this case, it is very convenient to use the enumerate()
function. Please refer to Looping Techniques for details.
It will be strange to print the result of range() directly:
>>> print(range(10))range(0, 10)
In many casesrange()
The returned object is like a list Same, but in fact it is not. When this object is iterated over, it returns consecutive items in the target sequence, but to save space, a list is not actually created.
This kind of object is called iterable
(iterable), that is, if some functions or structures expect to get consecutive items from something until the end, then iterable
Objects can meet this need. The for
statement is such an iterative program. list()
The function is another one that uses iterable objects to create lists:
>>> list(range(5)) [0, 1, 2, 3, 4]
We will introduce more about returning iterable objects and using iterable objects next function as a parameter.
break
and continue
Statements, and else
Clauses on LoopsLike C language, break The
statement jumps out of the innermost loop of for
or while
.
Loop statements can have else
clauses; when the for
loop completes traversing the loop sequence or the loop condition of the while
loop becomes When False
, the else
clause will be executed. But when the loop is terminated by the break
statement, the else
clause is not executed. The following example of finding prime numbers can prove this:
>>> 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 number3 is a prime number4 equals 2 * 25 is a prime number6 equals 2 * 37 is a prime number8 equals 2 * 49 equals 3 * 3
(The code is correct. Look closer: the else
clause belongs to the for
loop , instead of the if
statement. )
When used with a loop statement, the else
clause is more similar to the try
statement. The else
clause is similar, but different from the else
clause of the if
statement: when no exception occurs, the ## of the try
statement The #else clause will be executed. In the loop, when no
break occurs, the
else clause will be executed. For more information about
try statements and exceptions, see Handling Exceptions. The
continue statement is also borrowed from the C language and is used to jump directly to the next iteration of the loop:
>>> 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 2Found a number 3Found an even number 4Found a number 5Found an even number 6Found a number 7Found an even number 8Found a number 94.5 ## The #pass
statement does nothing. When a statement needs to be grammatically correct without doing anything, the pass
statement can be used . For example:
>>> while True: ... pass # Busy-wait for keyboard interrupt (Ctrl+C)...
pass
语句可以用来创建最小类:
>>> class MyEmptyClass: ... pass...
pass
语句的另一个用处是,当需要编写新的代码时,使用它作为函数或者条件体的位置占位符,这为作者在更加抽象的层次思考问题提供了便利。pass
被默默地忽视:
>>> def initlog(*args): ... pass # Remember to implement this!...
以下是打印任意边界斐波那契额数列的函数:
>>> 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
引入函数定义,必须在后面跟上函数名字和形参列表。构成函数体的语句另起一行,必须缩进。
函数体的第一条语句可以选择性使用字符串作为函数的文档字符串,或者docstring
。(更多关于文档字符串参见 Documentation Strings) 有许多工具使用文档字符串自动生成在线或者打印文档,或者允许使用者交互地浏览代码;在代码中写文档字符串是一个好的实践,因此需要将其作为习惯。
函数的执行引入了函数局部变量使用的新符号表。更准确的说,所有在函数中赋值变量都将值存储在局部符号表中;变量引用首先在局部符号表中查找,然后是封闭函数的局部符号表,然后是全局符号表,最后是built-in符号表。因此,在函数中全局变量可以被引用,但是不能直接赋予新值(除非使用global
语句声明)。
但函数被调用时,实参也被引入被调用函数的局部符号表中。因此,参数按照按值调用的方式传递(这里的值总是对象引用,而不是对象的值。)[1] 当函数调用其他函数时,为调用会产生新的局部符号表。
函数定义在当前符号表中引入函数名。函数名引用的值拥有一个被解释器识别为“用户自定义函数”的类型。这个值也可以赋值给其他名字,然后使用这个名字来调用函数。这种方式是函数重命名机制:
>>> fib<function fib at 10042ed0>>>> f = fib>>> f(100)0 1 1 2 3 5 8 13 21 34 55 89
拥有其他语言经验的程序员,可能会认为fib
不是一个方法而是一个过程,因为它没有返回值。事实上,没有返回语句的函数确实返回了值,而且是相当烦人的值,这个值被称为None
(built-in名字)。如果None
值是唯一要写的值,那么写的时候通常会被解释器忽视。使用print()
可以看到打印的None
值:
>>> fib(0)>>> print(fib(0))None
想要定义返回斐波那契数列数字而不是打印数字的函数非常简单:
>>> 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
。函数结束时也会返回`None。
语句result.append(a)
调用列表对象result
的方法。方法是属于对象的函数,并且以obj.methodname
命名,这里obj
是一个对象(或许是返回对象的表达式),methodname
是定义在obj
所属类型中的函数名。不容的类型定义了不同的函数。不同类型中的函数可以拥有相同的名字而不会导致二义(使用类,自定义新的对象类型和函数是可行的,参见Classes
) 这个例子中的方法append()
定义在列表对象中;该方法在列表末尾添加新元素。这个例子中等同于result = result + [a]
,但是append()
方法更加高效。
定义函数可以使用许多参数,有三种形式,可以将其结合使用。
为一个或者更多参数指定默认值是最有用的。这种方式创建的函数,可以使用比定义所需更少的参数来调用。例如:
def ask_ok(prompt, retries=4, reminder='Please try again!'):while True: ok = input(prompt)if ok in ('y', 'ye', 'yes'):return Trueif ok in ('n', 'no', 'nop', 'nope'):return Falseretries = retries - 1if 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 = 5def f(arg=i):print(arg) i = 6f()
会打印5。
重要提示: 参数默认值只被求值一次。当默认参数是诸如列表,字典或者其他大多数对象的可变对象时,会有很大不同。例如,以下函数累积后续调用传递的实参:
def f(a, L=[]): L.append(a)return Lprint(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
也可以使用如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 argumentparrot(voltage=1000) # 1 keyword argumentparrot(voltage=1000000, action='VOOOOOM') # 2 keyword argumentsparrot(action='VOOOOOM', voltage=1000000) # 2 keyword argumentsparrot('a million', 'bereft of life', 'jump') # 3 positional argumentsparrot('a thousand', state='pushing up the daisies') # 1 positional, 1 keyword
但是下面的调用方式都是非法的:
parrot() # required argument missingparrot(voltage=5.0, 'dead') # non-keyword argument after a keyword argumentparrot(110, voltage=220) # duplicate value for the same argumentparrot(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 <module>TypeError: function() got multiple values for keyword argument 'a'
当最一个的形参是**name
形式时,这个参数接收字典(参见 Mapping Types-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
注意关键字参数打印的顺序保证是与其在函数调用时提供的顺序相同的。
最后,最不常用的是让函数可以使用任意数量的参数调用。这些参数会被包装在元组中(参见 Tuples and Sequences)。在可变数量形参之前,可以有零个或者更多普通参数:
def write_multiple_items(file, separator, *args):file.write(separator.join(args))
通常,可变参数是形参列表中的最后一个,因为可变参数接收了传递给函数的所有剩余实参。出现在*args
后面的任意任意形参都是keyword-only
参数(强制关键字参数),意味着他们只能作为关键字参数使用,而不能用作位置参数。
>>> def concat(*args, sep="/"): ... return sep.join(args) ...>>> concat("earth", "mars", "venus")'earth/mars/venus'>>> concat("earth", "mars", "venus", sep=".")'earth.mars.venus'
参数已经封装在列表或者元组中,但是当调用需要分离的位置参数的函数时,需要拆包元组或者列表。例如,built-in函数range()
需要分离的start
和stop
参数。如果它们不是分离的,可以在函数调用时使用*
操作符来从列表或者元组中拆包(译注:事实证明,字符串也是可以被拆包的):
>>> 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 !
可以使用关键字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')]
这里有一些关于文档字符串的内容和格式的约定。
第一行应该是对象用途短小而简明地总结。简洁起见,不应该详细描述对象的名字和类型,因为可以通过其他途径了解(除非名字恰好是描述方法操作的动词)。这一行应该以大写字母开始并以句号结束。
如果文档字符串有多行,第二行应该空出来,从视觉上把总结和其他的描述分开来。剩余行应是一个或者多个描述对象的调用约定及其副作用的段落。
Python分析程序不会去掉多行字符串中的缩排,因此如果必要的话,文档处理工具自己必须去掉缩排,这遵循以下约定:第一行字符串后面的第一个非空行决定整个文档字符串缩排的数量。(因为第一行紧挨着它的起始引号,因此表面上看不出其缩排,所以不能使用第一行作为标准)留白“相当于”是字符串的起始缩排。每一行都不应该有缩排,如果有缩排的话,所有的留白都应该清除掉。留白的长度应当等于扩展制表符的宽度(通常是8个空格)。
以下是多行文档字符串的示例:
>>> 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.
方法注解 是描述用户自定义方法使用的类型的元信息,是完全可选的(参见PEP 484获取更多信息)。
注解作为字典存储在方法属性__annotations__
中,并且对方法的其他部分没有任何影响。参数注解定义在参数名字后的冒号后面,紧跟计算注解值得表达式。返回注解使用->
定义,紧跟表达式,在参数列表和指示def
语句结束的冒号中间。下面的例子有一个位置参数,关键字参数以及返回值得注解:
>>> 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'
现在需要写更长更复杂的Python程序,是时候谈论编码风格了。大多数语言可以以不同的风格编写(更简洁的说是格式化),一些编码风格比其他的更加可读。让其他人更容易读懂你的代码一直都是很重要的,养成良好的编码风格很重要。
对于Python来说,PEP 8被作为风格规范指导,许多项目都在使用这种规范。这个规范促成了一种非常易读和养眼的代码风格。在某种程度上每一个Python开发者都应该阅读它,以下是从这个规范中提取的重要内容:
使用4个空格作为缩进,而不是tab
4个空格是小的缩进(允许更深的嵌套深度)和大缩进(更易读)之间的良好折中方案。Tabs会导致困扰,最好弃用
换行以保证每一行不会超过79个字符
这在小的显示器上非常有用,也可在打的显示器中分屏显示多个文件
使用空行分开方法和类,以及函数中的大代码块
如果可能,注释独占一行
使用文档字符串
在操作符的两端以及顿号后面使用空格,但是不要在括号内侧使用:a = f(1, 2) + g(3, 4)
统一命名类以及函数;约定使用CamelCase
(驼峰)命名类,使用lower_case_with_underscores
(小写带下划线)命名方法和函数。总是使用self
作为方法的第一个参数名(参见A first Look at Classes了解更多关于类和方法的genggd)
如果代码要在国际环境中使用,不要使用自己喜爱的编码方式。Python的默认编码UTF-8
或者甚至普通的ASCII
编码都能在任何情况下起作用。
同样的,不要在标识符中使用非ASCII
字符,除非是不同语种的人会阅读和维护代码。
[1] 事实上,使用引用传递会更好,因为如果传递的是可变对象,变调用者对对象做的改变对调用者可见(如在列表中插入新的项)
The above is the detailed content of Detailed introduction to flow control statements in Python. For more information, please follow other related articles on the PHP Chinese website!