除了while刚才介绍的语句之外,Python还知道其他语言中常见的控制流程语句,并且有些曲折。

4.1。if陈述

也许最着名的陈述类型是if陈述。例如:

>>>

>>> x  =  int input “请输入一个整数:” ))
请输入一个整数:42 
>>> if  x  <  0 
...     x  =  0 
...     print 'Negative changed to zero' 
... elif  x  ==  0 
...     print 'Zero' 
... elif  x  ==  1 
...     print 'Single' 
... else 
...     打印'更多' 
... 
更多

可以有零个或多个elif零件,else零件是可选的。关键字’ elif‘是’else if’的缩写,对于避免过多的缩进非常有用。一 if… … elif… … elif… …序列的替代switch或 case其它语言中的语句。

4.2。for陈述

forPython中的语句与C或Pascal中的语句有所不同。Python的for语句并不是总是迭代数字的算术级数(比如在Pascal中),或者让用户能够定义迭代步骤和停止条件(如C),Python 语句迭代任何序列的项目(一个列表或一个字符串),按顺序出现在顺序中。例如(没有双关语意):

>>>

>>> #测量一些字符串:
... words  =  [ 'cat'  'window'  'defenestrate' ] 
>>> for  w  in  words 
...     print w  len w ))
... 
cat 3 
窗口6 
安静12

如果您需要在循环内部修改正在迭代的序列(例如复制选定的项目),建议您首先进行复制。迭代一个序列不会隐式地创建一个副本。切片符号使这特别方便:

>>>

>>> for  w  in  words [:]:  #循环遍历整个列表的切片副本。
...     如果 len w  >  6 
...         单词insert 0  w 
... 
>>> words 
['defenestrate','cat','window','defenestrate']

用这个例子会试图创建一个无限的列表,一遍又一遍地插入。for w in words:defenestrate

4.3。该range()功能

如果你需要遍历一系列的数字,内置函数 range()就派上用场了。它生成算术级数:

>>>

>>> for  i  in  range 5 ):
...     print i 
... 
0 
1 
2 
3 
4

给定的终点不是生成的序列的一部分; range(10)生成10个值,一个长度为10的序列的项目的合法索引。可以让范围从另一个数字开始,或者指定一个不同的增量(甚至是负数;有时这称为“步长”):

范围5  10 
   5   9

范围0  10  3 
   0  3  6  9

范围- 10  - 100  - 30 
  - 10  - 40  - 70

要遍历序列的指数,你可以结合range()和 len()如下:

>>>

>>> 一个 =  [ '玛丽'  '有'  'A'  '小'  '羊肉' ] 
>>> 用于   范围LEN )):
...     打印 一个[ ])
... 
0玛丽
1有
2 
3 3小
4羊肉

但是,在大多数情况下,使用该enumerate() 功能很方便,请参阅“ 循环技术”

一个奇怪的事情发生,如果你只是打印一个范围:

>>>

>>> print 范围10 ))
范围(0,10)

在许多方面,返回的对象的range()行为就好像它是一个列表,但事实上并非如此。它是一个对象,当你迭代它时,它返回所需序列的连续项,但它并不真正做出列表,从而节省了空间。

我们说这样的对象是可迭代的,也就是说,适合作为函数和构造的目标,期望从中可以获得连续的东西,直到耗尽为止。我们已经看到这个for陈述是这样一个迭代器。功能list() 是另一个; 它从迭代中创建列表:

>>>

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

之后我们会看到更多函数返回迭代器,并将迭代器作为参数。

4.4。breakcontinue语句,以及else循环中的子句

这个break陈述就像在C中一样,突破了最内层的封闭 forwhile循环。

循环语句可能有一个else子句; 当循环通过用尽列表(with for)或者当条件变为false(with while)时循环终止,但是当循环由break语句终止时执行。以下面的循环为例,它搜索素数:

>>>

>>>  Ñ   范围2  10 ):
...      X   范围2  Ñ ):
...         如果 ñ   X  ==  0 
...             打印Ñ  '等于'  X  '*'  n // x 
...             break 
...     else 
...         #循环没有找到一个因素
...         print Ñ  “是素数” 
... 
2是一个素数
3是质数
4等于2 * 2 
5是素数
6等于2 * 3 
图7是一个素数
8等于2 * 4 
9等于3 * 3

(是的,这是正确的代码,仔细一看:该else条款属于for循环,不是if。陈述)

与循环else一起使用时,else子句与try语句 的子句有更多的相同之处 iftry语句的else子句在没有发生异常时else运行,当没有break 发生时运行循环的子句。有关try语句和例外的更多信息,请参阅 处理例外

continue从C中借用的语句继续循环的下一次迭代:

>>>

>>>  NUM   范围2  10 ):
...     如果 NUM   2  ==  0 
...         打印“找到偶数”  NUM 
...         继续
...     打印“发现一个号码 数字
找到一个偶数2 
找到一个数字3 
找到一个偶数4 
找到一个数字5 
找到一个偶数6 
找到一个数字7 
找到一个偶数8 
找到一个数字9

4.5。pass陈述

pass语句什么也不做。当语句需要语法时可以使用它,但程序不需要任何操作。例如:

>>>

>>> while  True 
...     pass   #繁忙 - 等待键盘中断(Ctrl + C)
...

这通常用于创建最小类:

>>>

>>> class  MyEmptyClass 
...     传递
...

另一个地方pass可以被用来作为一个函数或条件体的占位符,当你正在处理新的代码时,允许你继续思考一个更抽象的层次。这pass是无声的忽略:

>>>

>>> def  initlog * args ):
...     传递   #记得实现这个!
...

4.6。定义功能

我们可以创建一个将斐波那契数列写入任意边界的函数:

>>>

>>> DEF  撒谎Ñ ):     #写斐波纳契数列多达n 
...     “” “打印斐波纳契数列多达n” “” 
...     一个 b  =  0  1 
...      一个 <  Ñ 
...         print a  end = '' 
...         a  b  =  b  a + b 
...     print ()
... 
>>> #现在调用刚刚定义的函数:
...fib 2000 
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597

关键字def引入了一个函数定义。它必须跟随函数名称和形式参数的括号括起来的列表。构成函数主体的语句从下一行开始,并且必须缩进。

函数体的第一个语句可以可选地是一个字符串文字; 这个字符串文字是函数的文档字符串,或docstring。(有关文档字符串的更多信息,请参见文档字符串部分。)有一些工具可以使用文档自动生成在线或打印文档,或者让用户交互式地浏览代码; 将文档包含在您编写的代码中是一个很好的做法,所以养成一个习惯。

函数的执行引入了一个用于函数局部变量的新符号表。更确切地说,函数中的所有变量赋值都将该值存储在本地符号表中; 而变量引用首先在本地符号表中查找,然后在封闭函数的本地符号表中,然后在全局符号表中,最后在内置名称表中查找。因此,全局变量不能直接在函数中赋值(除非在global语句中命名),尽管它们可能被引用。

函数调用的实际参数(参数)在被调用函数的本地符号表中被引入,因此,通过值调用传递参数(其中始终是对象引用,而不是对象的值)。[1]当函数调用另一个函数时,为该调用创建一个新的本地符号表。

函数定义在当前符号表中引入函数名称。函数名的值有一个被解释器识别为用户定义函数的类型。这个值可以分配给另一个名字,然后也可以作为一个函数使用。这是一个通用的重命名机制:

>>>

>>> 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通常被解释器抑制,如果它是唯一写入的值。你可以看到它,如果你真的想使用print()

>>>

>>> fib 0 
>>> print fib 0 ))

编写一个返回斐波那契数列表的函数,而不是打印它的函数很简单:

>>>

>>> def  fib2 n ):  #返回斐波那契数列到n 
...     “”“返回包含斐波那契数列的列表,最多为n。”“” 
...     result  =  [] 
...     a  b  =  0  1 
...      一个 <  ñ 
...         结果追加a     #见下面
...         a  b  =  b  a + b 
...     返回 结果
...
>>> f100  =  fib2 100     #call it 
>>> f100                 #将结果写入
[ 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是由对象的类型定义的方法的名称。不同类型定义不同的方法。不同类型的方法可能具有相同的名称而不会造成歧义。(可以使用定义您自己的对象类型和方法,请参见append()示例中显示的方法是为列表对象定义的; 它在列表的末尾添加了一个新的元素。在这个例子中,它相当于 ,但更有效。result = result + [a]

4.7。更多关于定义函数

也可以使用可变数量的参数来定义函数。有三种形式,可以合并。

4.7.1。默认参数值

最有用的形式是为一个或多个参数指定一个默认值。这创建了一个函数,可以使用比它定义允许的参数更少的参数来调用。例如:

高清 ask_ok 提示 重试= 4  提醒= '请重试!' ):
     
        OK  =  输入提示
        ,如果 确定  'Y'  '叶'  '是' ):
            返回 
        ,如果 确定  'n'  'no'  'nop'  'nope' ):
            return  False 
        retries  =  retries  - 1 
        如果 重试 <  0 
            提高 ValueError '无效用户响应' 
        打印提醒

这个函数可以通过几种方式调用:

  • 只给出强制性的论点: 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关键字。这测试一个序列是否包含一个确定的值。

默认值是在定义范围的函数定义处计算的

 =  5

def  f arg = i ):
    print arg 

 =  6 
f ()

将打印5

重要警告: 默认值只计算一次。当默认值是可变对象(如列表,字典或大多数类的实例)时,这会有所不同。例如,下面的函数累积在后续调用中传递给它的参数:

def  f a  L = []):
    L 追加a 
    返回 L

print f 1 ))
print f 2 ))
print f 3 ))

这将打印

[ 1 ] 
[ 1  2 ] 
[ 1  2  3 ]

如果你不想在后续调用之间共享默认值,你可以这样写:

DEF  ˚F 一个 大号= ):
    如果 大号  
        大号 =  [] 
    大号追加a 
    返回 L

4.7.2。关键字参数

函数也可以使用 表单的关键字参数来调用kwarg=value。例如,以下功能:

高清 鹦鹉电压 状态= “硬”  行动= “VOOM”  类型= “挪威蓝” ):
    打印“ -此鹦鹉会不会”  行动 结束= “” 
    打印“如果你放”  电压 ‘伏特通过它’。 
    打印‘ -可爱的羽毛,在’  类型
    打印‘ -这是’  状态 “!”

接受一个所需参数(voltage)和三个可选参数(stateaction,和type)。这个函数可以通过以下任何一种方式调用:

鹦鹉1000                                           #1位置参数
鹦鹉电压= 1000                                   #1关键字参数
鹦鹉电压= 百万 动作= 'VOOOOOM'              #2关键字参数
鹦鹉动作= 'VOOOOOM'  电压= 百万             #2关键字参数
鹦鹉“百万”  “被剥夺生命”  “跳”          #3位置参数
鹦鹉'千'  状态= '推雏菊'   #1位置,1个关键字

但以下所有电话都是无效的:

parrot ()                     #需要的参数丢失
鹦鹉电压= 5.0  '死亡'   #关键字参数后的非关键字参数
鹦鹉110  电压= 220      #重复值为同一参数
鹦鹉actor = '约翰Cleese'   #未知的关键字参数

在函数调用中,关键字参数必须跟随位置参数。所有传递的关键字参数必须与函数接受的参数之一相匹配(例如actor,不是函数的有效参数 parrot),它们的顺序并不重要。这也包括非可选参数(例如parrot(voltage=1000)也是有效的)。没有参数可能会多次收到一个值。这是一个由于这个限制而失败的例子:

>>>

>>> DEF  功能):
...     传递
... 
>>> 功能0  一个= 0 
回溯(最近最后调用):
  文件“<标准输入>” ,线1 ,在<模块> 
类型错误函数()有多个值的关键字参数'一'

当表单的最后一个形式参数**name出现时,它接收一个包含所有关键字参数的字典(参见映射类型 – dict),除了那些对应于形式参数的参数。这可以与形式的形式参数*name(在下一小节中描述)相结合,其接收包含形式参数列表之外的位置参数的元组。(*name之前必须发生**name)。例如,如果我们定义一个这样的函数:

def  cheeseshop kind  * arguments  ** keywords ):
    print “ - 你有什么”  kind  “?” 
    print “ - 对不起,我们都没有了”  kind 
    对于 arg  中的 参数
        print arg 
    print “ - ”  *  40 
    for  kw  in  keywords 
        print kw  “:”  关键字[ kw ])

它可以这样调用:

奶酪店“Limburger”  “非常流鼻涕,先生” 
           “真的非常非常流鼻涕,先生。” 
           店主= “Michael Palin” 
           客户= “John Cleese” 
           素描= “奶酪店素描” 

当然它会打印:

 - 你有林堡吗?
- 对不起,我们全都出了Limburger
先生,这很流鼻血。
先生,真的非常非常流鼻涕
----------------------------------------
店主:迈克尔·佩林
客户:John Cleese
素描:奶酪店素描

请注意,打印关键字参数的顺序保证与它们​​在函数调用中提供的顺序相匹配。

4.7.3。任意参数列表

最后,最不经常使用的选项是指定可以用任意数量的参数调用一个函数。这些参数将被包装在一个元组中(参见元组和序列)。在可变数量的参数之前,可能会出现零个或多个正常参数。

def  write_multiple_items 文件 分隔符 * 参数):
    文件分隔符加入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。解压参数列表

当参数已经在列表或元组中时,会出现相反的情况,但需要对需要单独位置参数的函数调用进行解压缩。例如,内置range()函数需要单独的 启动停止参数。如果它们不能单独使用,请使用*-operator 编写函数调用以 将参数解开列表或元组:

>>>

>>> 列表范围3  6 ))             #正常呼叫,独立参数
[3,4,5] 
>>> ARGS  =  [ 3  6 ] 
>>> 列表范围* ARGS ))             #呼叫与参数从列表中解压缩
[3,4,5]

以同样的方式,字典可以用**-operator 提供关键字参数:

>>>

>>> def  parrot voltage  state = 'a stiff'  action = 'voom' ):
...     print “ - this parrot would”  action  end = '' 
...     print “如果你把”  电压 “通过它伏。”  结束= '' 
...     打印“E的”  状态 “!” 
...
>>> d =  { “电压”  “四千万”  “状态”  “流血批租”  ‘行动’  ‘VOOM’ } 
>>> 鹦鹉** d 
-如果你放四个此鹦鹉会不会VOOM百万伏特通过它。E的流血消失了!

4.7.5。Lambda表达式

小的匿名函数可以用lambda关键字创建。这个函数返回两个参数的总和:。可以在需要函数对象的地方使用Lambda函数。它们在语法上受限于单个表达式。在语义上,它们只是正常函数定义的语法糖。像嵌套函数定义一样,lambda函数可以引用来自包含范围的变量:lambda a, b: a+b

>>>

>>> 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中的多行字符串文字中去除缩进,所以如果需要,处理文档的工具必须去除缩进。这是使用以下惯例完成的。字符串的第一行之后的第一个非空行 确定整个文档字符串的缩进量。(我们不能使用第一行,因为它通常与字符串的开始引号相邻,所以它的缩进在字符串文字中是不明显的)。然后从字符串的所有行的开头剥离与该缩进等效的空格。缩进的行不应该出现,但是如果它们出现,则应删除所有前导空白。在标签扩展后(通常为8个空格),应该测试空白的等效性。

这是一个多行文档字符串的例子:

>>>

>>> def  my_function ():
...     “”“什么也不做,但要记录下来
...
......     不,真的,它不会做任何事情。
......     “”” 
......     通过
... 
>>> 打印创建my_function __doc__ 
什么都不做,而是将其记录下来。

    不,真的,它什么都不做。

4.7.7。函数注释

函数注释是关于用户定义函数使用的类型的完全可选的元数据信息(请参阅PEP 484 了解更多信息)。

注解__annotations__作为字典存储在函数的属性中,并且不影响函数的其他部分。参数注释由参数名称后面的冒号定义,后跟一个表达式,以评估注释的值。返回注释由一个文字定义->,后跟一个表达式,在参数列表和冒号之间,表示def语句的结尾。以下示例具有位置参数,关键字参数和注释的返回值:

>>>

>>> DEF  ˚F 火腿 STR  鸡蛋 STR  =  '蛋'  - >  STR 
...     打印“注解:”  ˚F __annotations__ 
...     打印“参数:”  火腿 鸡蛋
...     返回 火腿 +  '和'  +  
... 
>>> f '垃圾' 
注释:{'ham':<class'str'>,'return':<class'str'>,'eggs':<class'str'>} 
参数:spam 
eggs'spam and eggs'

4.8。间奏曲:编码风格

现在您要编写更长,更复杂的Python,现在是讨论编码风格的好时机。大多数语言都可以用不同的风格写成(或更简洁,格式化)有些比其他更可读。让他人阅读你的代码容易,总是一个好主意,采用一个不错的编码风格是非常有帮助的。

对于Python, PEP 8已经成为大多数项目所遵循的风格指南; 它促进了非常可读和令人愉悦的编码风格。每个Python开发者都应该读一下它; 这里是为你提取的最重要的点:

  • 使用4空格缩进,并没有选项卡。

    4个空格是小缩进(允许更大的嵌套深度)和大缩进(更容易读取)之间的良好折衷。标签引入混淆,并最好省略。

  • 包装线不要超过79个字符。

    这可以帮助用户使用小型显示器,并可以在较大的显示器上并排显示多个代码文件。

  • 使用空行来分隔函数和类,以及函数内的更大的代码块。

  • 在可能的情况下,对他们自己的一行进行评论。

  • 使用docstrings。

  • 在运算符和逗号后面使用空格,但不要直接在包围结构中使用空格:。a = f(1, 2) + g(3, 4)

  • 一致地命名你的类和函数; 该惯例是 CamelCase用于类和lower_case_with_underscores功能和方法。始终self用作第一个方法参数的名称(有关类和方法的更多信息,请参见首先查看类)。

  • 如果您的代码旨在用于国际环境,请不要使用奇特的编码。Python的默认,UTF-8甚至纯ASCII在任何情况下都是最好的。

  • 同样,不要在标识符中使用非ASCII字符,如果只有轻微的机会,说不同的语言会读取或维护代码。

脚注

[1] 实际上,通过对象引用调用将是一个更好的描述,因为如果一个可变对象被传递,调用者将看到被调用者对它所做的任何改变(插入到列表中的项目)。