Maison  >  Article  >  développement back-end  >  Introduction détaillée aux instructions de contrôle de flux en Python

Introduction détaillée aux instructions de contrôle de flux en Python

零下一度
零下一度original
2017-07-18 10:30:482312parcourir

En plus de l'instruction while qui vient d'être introduite, Python emprunte également d'autres instructions de contrôle de flux à d'autres langages et apporte les modifications correspondantes. Introduction détaillée aux instructions de contrôle de flux en Python

4.1 if Déclarations

L'instruction la plus connue est peut-être l'instruction if. Par exemple :

x = int(input("Please enter an integer: "))if x < 0:
    x = 0print(&#39;Negative changed to zero&#39;)elif x == 0:print(&#39;Zero&#39;)elif x == 1:print(&#39;Single&#39;)else:print(&#39;More&#39;)

peut avoir zéro ou plusieurs clauses elif, et les clauses else sont facultatives. Le mot-clé elif est une forme intermittente de else if, ce qui peut éviter une indentation excessive. La séquence if ... elif ... elif ... remplace les instructions switch ou case dans d'autres langues.

4.2 for Déclarations

L'instruction for en Python est légèrement différente de l'instruction for en C ou Pacsal. Python n'utilise pas la méthode d'itération des numéros de séquence arithmétique (en Pascal) pour implémenter des boucles, ni la méthode de définition du nombre d'étapes d'itération et des conditions d'arrêt comme le langage C pour implémenter les boucles. L'instruction for de Python peut être utilisée. dans n'importe quelle séquence. Parcourt les éléments (liste ou chaîne) dans l'ordre dans lequel ils apparaissent dans la séquence. Par exemple (pas d'autre sens) :

# Measure some strings:words = [&#39;cat&#39;, &#39;window&#39;, &#39;defenestrate&#39;]for w in words:print(w, len(w))

Si vous devez modifier la séquence parcourue dans la boucle (comme copier l'élément sélectionné), il est recommandé de copier le séquence en premier. Aucune sauvegarde n'est implicitement créée lors du parcours de la séquence. Les instructions de découpage sont particulièrement pratiques pour copier des séquences :

for w in words[:]:  # Loop over a slice copy of the entire list.if len(w) > 6:
        words.insert(0, w)
words

Avec for w in words:O, l'instance tentera de créer une liste infinie, en insérant constamment la chaîne defenestrate.

4.3 La range() Fonction

Si vous avez vraiment besoin de parcourir une séquence de nombres, la fonction intégrée range() peut s'avérer utile. Cette fonction génère une séquence arithmétique :

>>> for i in range(5):
...     print(i)
...01234

endLes paramètres ne seront pas inclus dans la séquence générée range(10) génère 10 valeurs, la longueur d'index légale de la séquence ; l'article est 10. Vous pouvez commencer la plage à un autre nombre ou spécifier un incrément différent (même un nombre négatif ; parfois l'incrément est appelé un « étape ») :

range(5, 10)   5 through 9range(0, 10, 3)   0, 3, 6, 9range(-10, -100, -30)  -10, -40, -70

requis lors d'une itération l'index d'une séquence, vous pouvez combiner les fonctions range() et len() comme ceci :

>>> a = [&#39;Mary&#39;, &#39;had&#39;, &#39;a&#39;, &#39;little&#39;, &#39;lamb&#39;]>>> for i in range(len(a)):
...     print(i, a[i])
...0 Mary1 had2 a3 little4 lamb

Cependant, dans la plupart de ces cas, utilisez enumerate()La fonction est très pratique, veuillez vous référer aux Techniques de bouclage pour plus de détails.

Il serait étrange d'imprimer directement le résultat de range() :

>>> print(range(10))range(0, 10)

Dans de nombreux cas range() l'objet renvoyé est comme une liste, mais en fait, ce n'est pas le cas. Lorsque cet objet est itéré, il renvoie des éléments consécutifs dans la séquence cible, mais pour économiser de l'espace, une liste n'est pas réellement créée.

Ce type d'objet est appelé iterable (itérable), c'est-à-dire que si certaines fonctions ou structures s'attendent à obtenir des éléments consécutifs de quelque chose jusqu'à la fin, alors l'objet iterable peut satisfaire ce besoin. L'instruction for est un programme tellement itératif. list()La fonction est une autre fonction qui crée une liste à l'aide d'objets itérables :

>>> list(range(5))
[0, 1, 2, 3, 4]

D'autres fonctions qui renvoient des objets itérables et prennent des objets itérables comme paramètres seront introduites ensuite.

4.4 Instructions break et continue, et else Clauses sur les boucles

Comme le langage C, l'instruction break sort du niveau le plus interne de for ou whilecycle. Les instructions de boucle

peuvent avoir des clauses else ; lorsque la boucle for termine de parcourir la séquence de boucle ou que la condition de boucle de la boucle while devient False, la clause else sera exécutée . Mais lorsque la boucle se termine par l'instruction break, la clause else n'est pas exécutée. Ceci est démontré par l'exemple suivant de recherche de nombres premiers :

>>> for n in range(2, 10):
...     for x in range(2, n):
...         if n % x == 0:
...             print(n, &#39;equals&#39;, x, &#39;*&#39;, n//x)
...             break...     else:
...         # loop fell through without finding a factor...         print(n, &#39;is a prime number&#39;)
...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

(Le code est correct. Regardez de plus près : la clause else appartient à la boucle for, pas à l'instruction if. )

Lorsqu'elle est utilisée avec une boucle, la clause else ressemble plus à la clause try de l'instruction else qu'à la clause if de l' else. 🎜>. Les phrases sont différentes : lorsqu'aucune exception ne se produit, la clause try de l'instruction else sera exécutée. Dans la boucle, lorsqu'aucune exception break ne se produit, la clause else sera exécutée. Pour plus d’informations sur les instructions et exceptions try, consultez Gestion des exceptions. L'instruction

continue est également empruntée au langage C et permet de passer directement à l'itération suivante de la boucle :

>>> 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 9

4.5 pass Déclarations L'instruction

pass ne fait rien Lorsqu'une instruction doit être grammaticalement correcte sans rien faire, l'instruction pass peut être utilisée. Par exemple :

>>> while True:
...     pass  # Busy-wait for keyboard interrupt (Ctrl+C)...

pass语句可以用来创建最小类:

>>> class MyEmptyClass:
...     pass...

pass语句的另一个用处是,当需要编写新的代码时,使用它作为函数或者条件体的位置占位符,这为作者在更加抽象的层次思考问题提供了便利。pass被默默地忽视:

>>> def initlog(*args):
...     pass   # Remember to implement this!...

4.6 Defining Functions

以下是打印任意边界斐波那契额数列的函数:

>>> 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=&#39; &#39;)
...         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()方法更加高效。

4.7 More on Defining Functions

定义函数可以使用许多参数,有三种形式,可以将其结合使用。

4.7.1 Default Argument Values

为一个或者更多参数指定默认值是最有用的。这种方式创建的函数,可以使用比定义所需更少的参数来调用。例如:

def ask_ok(prompt, retries=4, reminder=&#39;Please try again!&#39;):while True:
        ok = input(prompt)if ok in (&#39;y&#39;, &#39;ye&#39;, &#39;yes&#39;):return Trueif ok in (&#39;n&#39;, &#39;no&#39;, &#39;nop&#39;, &#39;nope&#39;):return Falseretries = retries - 1if retries < 0:raise ValueError(&#39;invalid user response&#39;)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

4.7.2 Keyword Arguments

也可以使用如kwarg = value形式的关键字参数调用函数。例如如下函数:

def parrot(voltage, state=&#39;a stiff&#39;, action=&#39;voom&#39;, type=&#39;Norwegian Blue&#39;):print("-- This parrot wouldn&#39;t", action, end=&#39; &#39;)print("if you put", voltage, "volts through it.")print("-- Lovely plumage, the", type)print("-- It&#39;s", state, "!")

接受一个必须参数(voltage)以及三个可选参数(state, actiontype)。这个函数可以使用以下的任意方式调用:

parrot(1000)                                          # 1 positional argumentparrot(voltage=1000)                                  # 1 keyword argumentparrot(voltage=1000000, action=&#39;VOOOOOM&#39;)             # 2 keyword argumentsparrot(action=&#39;VOOOOOM&#39;, voltage=1000000)             # 2 keyword argumentsparrot(&#39;a million&#39;, &#39;bereft of life&#39;, &#39;jump&#39;)         # 3 positional argumentsparrot(&#39;a thousand&#39;, state=&#39;pushing up the daisies&#39;)  # 1 positional, 1 keyword

但是下面的调用方式都是非法的:

parrot()                     # required argument missingparrot(voltage=5.0, &#39;dead&#39;)  # non-keyword argument after a keyword argumentparrot(110, voltage=220)     # duplicate value for the same argumentparrot(actor=&#39;John Cleese&#39;)  # 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 &#39;a&#39;

当最一个的形参是**name形式时,这个参数接收字典(参见 Mapping Types-dict),这个字典包含不能能与形参对应的关键字实参。关键字参数可以与形如*name的形式参数结合,这种形式参数以元组接收不能与形参匹配的位置参数。(*name必须在**name之前)。例如,以下函数:

def cheeseshop(kind, *arguments, **keywords):print("-- Do you have any", kind, "?")print("-- I&#39;m sorry, we&#39;re all out of", kind)for arg in arguments:print(arg)print("-" * 40)for kw in keywords:print(kw, ":", keywords[kw])

可以像下面一样调用:

cheeseshop("Limburger", "It&#39;s very runny, sir.",           "It&#39;s really very, VERY runny, sir.",
           shopkeeper="Michael Palin",
           client="John Cleese",
           sketch="Cheese Shop Sketch")

当然会如下打印:

-- Do you have any Limburger ?-- I&#39;m sorry, we&#39;re all out of Limburger
It&#39;s very runny, sir.It&#39;s really very, VERY runny, sir.----------------------------------------shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch

注意关键字参数打印的顺序保证是与其在函数调用时提供的顺序相同的。

4.7.3 Arbitrary Argument Lists

最后,最不常用的是让函数可以使用任意数量的参数调用。这些参数会被包装在元组中(参见 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")&#39;earth/mars/venus&#39;>>> concat("earth", "mars", "venus", sep=".")&#39;earth.mars.venus&#39;

4.7.4 Unpacking Argument Lists

参数已经封装在列表或者元组中,但是当调用需要分离的位置参数的函数时,需要拆包元组或者列表。例如,built-in函数range()需要分离的startstop参数。如果它们不是分离的,可以在函数调用时使用*操作符来从列表或者元组中拆包(译注:事实证明,字符串也是可以被拆包的):

>>> 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=&#39;a stiff&#39;, action=&#39;voom&#39;):
...     print("-- This parrot wouldn&#39;t", action, end=&#39; &#39;)
...     print("if you put", voltage, "volts through it.", end=&#39; &#39;)
...     print("E&#39;s", state, "!")
...>>> d = {"voltage": "four million", "state": "bleedin&#39; demised", "action": "VOOM"}>>> parrot(**d)-- This parrot wouldn&#39;t VOOM if you put four million volts through it. E&#39;s bleedin&#39; demised !

4.7.5 Lambda Expressions

可以使用关键字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, &#39;one&#39;), (2, &#39;two&#39;), (3, &#39;three&#39;), (4, &#39;four&#39;)]>>> pairs.sort(key=lambda pair: pair[1])>>> pairs
[(4, &#39;four&#39;), (1, &#39;one&#39;), (3, &#39;three&#39;), (2, &#39;two&#39;)]

4.7.6 Documentation Strings

这里有一些关于文档字符串的内容和格式的约定。

第一行应该是对象用途短小而简明地总结。简洁起见,不应该详细描述对象的名字和类型,因为可以通过其他途径了解(除非名字恰好是描述方法操作的动词)。这一行应该以大写字母开始并以句号结束。

如果文档字符串有多行,第二行应该空出来,从视觉上把总结和其他的描述分开来。剩余行应是一个或者多个描述对象的调用约定及其副作用的段落。

Python分析程序不会去掉多行字符串中的缩排,因此如果必要的话,文档处理工具自己必须去掉缩排,这遵循以下约定:第一行字符串后面的第一个非空行决定整个文档字符串缩排的数量。(因为第一行紧挨着它的起始引号,因此表面上看不出其缩排,所以不能使用第一行作为标准)留白“相当于”是字符串的起始缩排。每一行都不应该有缩排,如果有缩排的话,所有的留白都应该清除掉。留白的长度应当等于扩展制表符的宽度(通常是8个空格)。

以下是多行文档字符串的示例:

>>> def my_function():
...     """Do nothing, but document it.......     No, really, it doesn&#39;t do anything....     """...     pass...>>> print(my_function.__doc__)
Do nothing, but document it.

    No, really, it doesn&#39;t do anything.

4.7.7 Documentation Strings

方法注解 是描述用户自定义方法使用的类型的元信息,是完全可选的(参见PEP 484获取更多信息)。

注解作为字典存储在方法属性__annotations__中,并且对方法的其他部分没有任何影响。参数注解定义在参数名字后的冒号后面,紧跟计算注解值得表达式。返回注解使用->定义,紧跟表达式,在参数列表和指示def语句结束的冒号中间。下面的例子有一个位置参数,关键字参数以及返回值得注解:

>>> def f(ham: str, eggs: str = &#39;eggs&#39;) -> str:
...     print("Annotations:", f.__annotations__)
...     print("Arguments:", ham, eggs)
...     return ham + &#39; and &#39; + eggs
...>>> f(&#39;spam&#39;)
Annotations: {&#39;ham&#39;: <class &#39;str&#39;>, &#39;return&#39;: <class &#39;str&#39;>, &#39;eggs&#39;: <class &#39;str&#39;>}
Arguments: spam eggs&#39;spam and eggs&#39;

4.7.8 Intermezzo: Coding Style

现在需要写更长更复杂的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字符,除非是不同语种的人会阅读和维护代码。

Footnotes

[1] 事实上,使用引用传递会更好,因为如果传递的是可变对象,变调用者对对象做的改变对调用者可见(如在列表中插入新的项)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn