Python3.7官方向导翻译之Python控制流工具

本文翻译自Python3.7向导

if 语句

x = int(input("please enter an integer:"))
please enter an integer:52
if x < 0:
    x = 0
    print('Negative changed to zerp')
elif x == 0:
    print('zero')
elif x == 1:
    print('Single')
else:
    print('More')
More

for 语句

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

words = ['cat', 'window', 'defenestrate']
for w in words:
    print(w, len(w))
cat 3
window 6
defenestrate 12

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

for w in words[:]:
    if len(w) > 6:
        words.insert(0, w)

words
['defenestrate', 'cat', 'window', 'defenestrate']

range()函数

如果您确实需要遍历一系列数字,则内置函数范围()将派上用场。 它生成算术级数:

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

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

range(5, 10)
range(5, 10)
range(0, 10, 2)
range(0, 10, 2)
range(-10, -100, -30)
range(-10, -100, -30)

要迭代序列的索引,可以按如下方式组合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()返回的对象的行为就好像它是一个列表,但事实上并非如此。 它是一个对象,它在您迭代时返回所需序列的连续项,但它并不真正生成列表,从而节省空间。
我们说这样一个对象是可迭代的,也就是说,适合作为函数和构造的目标,期望它们可以从中获得连续项,直到耗尽。 我们已经看到for语句就是这样一个迭代器。 函数list()是另一个; 它会根据迭代创建列表:

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

break 和 continue 语句

扫描二维码关注公众号,回复: 1586532 查看本文章

break语句,跳出最内层的for和while循环,和c一样。
循环语句可能有一个else从句(clause); 当循环通过用尽列表(用for)或条件变为false(用while)时循环终止时执行,但当循环由break语句终止时执行。 这由以下循环来举例说明,该循环搜索素数:

for n in range(2, 10):
    for x in range(2, n):
        if n % x == 0:
            print(n, 'equals', x, 'x', n//x)
            break
        else:
            print(n, 'is a prime number')
3 is a prime number
4 equals 2 x 2
5 is a prime number
5 is a prime number
5 is a prime number
6 equals 2 x 3
7 is a prime number
7 is a prime number
7 is a prime number
7 is a prime number
7 is a prime number
8 equals 2 x 4
9 is a prime number
9 equals 3 x 3

与循环一起使用时,else子句与try语句一块相比它与if语句更常用:try语句的else子句在没有发生异常时运行,并且在没有发生中断时运行循环的else子句。 有关try语句和异常的更多信息,请参阅处理异常。
continue语句,借鉴自c语言,继续下一个循环

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

pass 语句

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

while True:
    pass #busy-wait for keyboard interrupt

它通常用来创建迷你类

class MyEmptyClass:
    pass

另一个地方pass可以用于当您处理新代码时作为函数或条件体的占位符(place-holder),使您可以继续思考更抽象的级别。

def initlog(*args):
    pass #remember to implement it

定义函数

我们可以创建一个函数,它能够写任意(arbitrary)边界的菲波那切数列

def fib(n):
    """Print a Fibonacci series up to n"""

    a, b = 0, 1
    while a < n:
        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。 (关于文档字符串的更多信息可以在文档字符串部分找到。)有一些工具可以使用文档自动生成在线或打印文档,或让用户交互式浏览代码;在您编写的代码中包含文档字符串是一种很好的做法,所以养成它的习惯。

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

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

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

fib
<function __main__.fib(n)>
f = fib
f(100)
0 1 1 2 3 5 8 13 21 34 55 89 

来自其他语言,你可能会反对说fib不是一个函数,而是一个过程,因为它不返回一个值。 事实上,即使没有return语句的函数也会返回一个值,尽管这是一个相当枯燥的值。 这个值被称为无(这是一个内置的名称)。 写入值None通常会被解释器抑制,如果它是唯一写入的值。 你可以看到它,如果你真的想使用print():

fib(0)
print(fib(0))
None

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

def fib2(n):
    """Return a list containing the Fibonacci series up to n."""""
    result = []
    a, b = 0, 1
    while a < n:
        result.append(a)
        a, b = b, a+b   
    return result

f100 = fib2(100)
f100
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

关于函数定义的更多信息

默认参数值

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

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(’你真的想退出吗?’)
给出一个可选的参数:ask_ok(’确定覆盖文件?’,2)
或者甚至给出所有参数:ask_ok(’确定覆盖文件?’,2,’来吧,只有是或不是!’)

ask_ok('sdf')
sdfsdf
Please try again!

这个例子还介绍了in关键字。 这测试一个序列是否包含某个值。

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

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

print(f(1))
print(f(2))
print(f(3))
[1]
[2]
[3]

关键字参数(keyword arguments)

函数也可以通过使用形如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)和三个可选参数(状态,动作和类型)。 该功能可以通过以下任何方式调用:

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
-- This parrot wouldn't voom if you put 1000 volts through it
-- Lovely plumage, the Norwegian Blue
--It's a stiff !
-- This parrot wouldn't voom if you put 1000 volts through it
-- Lovely plumage, the Norwegian Blue
--It's a stiff !
-- This parrot wouldn't VOOOOOM if you put 1000000 volts through it
-- Lovely plumage, the Norwegian Blue
--It's a stiff !
-- This parrot wouldn't VOOOOOM if you put 1000000 volts through it
-- Lovely plumage, the Norwegian Blue
--It's a stiff !
-- This parrot wouldn't jump if you put a million volts through it
-- Lovely plumage, the Norwegian Blue
--It's bereft of life !
-- This parrot wouldn't voom if you put a thousand volts through it
-- Lovely plumage, the Norwegian Blue
--It's pushing up the daisies !

但下面的调用无效:

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
  File "<ipython-input-7-2ac707ad11c1>", line 2
    parrot(voltage=5.0, 'dead')  # non-keyword argument after a keyword argument
                       ^
SyntaxError: non-keyword arg after keyword arg

在函数调用中,关键字参数必须跟在位置参数后面(position arguments),所有传递的关键字参数必须与函数接受的参数之一相匹配(例如,参与者不是鹦鹉函数的有效参数),它们的顺序并不重要。这也包括非可选参数(例如parrot(voltage = 1000)也是有效的)。没有参数可以多次接受一个值

def function(a):
    pass
function(0, a=0)
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

<ipython-input-8-c27f71aecf56> in <module>()
      1 def function(a):
      2     pass
----> 3 function(0, a=0)


TypeError: function() got multiple values for argument 'a'

当最后的形式参数(formal parameter)以**name的形式出现时,它接受包含除了那些与形参对应的所有的关键字参数的字典。它可以与形式为*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.
----------------------------------------
client : John Cleese
shopkeeper : Michael Palin
sketch : Cheese Shop Sketch

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

任意参数列表

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

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'

解压参数列表

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

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

def make_incrementor(n):
    return lambda x: x + n

f = make_incrementor(42)
f(0)
42
f(2)
44

上面的例子使用一个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解析器不会从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.

功能注释function annotations

功能注释完全是有关用户定义函数使用的类型的可选元数据信息(有关更多信息,请参阅PEP 3107和PEP 484)。
注释以字典的形式存储在函数的annotations属性中,并且不影响函数的其他部分。 参数注释由参数名称后面的冒号(colon)定义,后跟表达式评估注释的值。 返回注释由参数列表和表示def语句结束的冒号之间的literal - >,后跟一个表达式定义。 以下示例具有位置参数,关键字参数和注释的返回值:

def f(ham: str, eggs: str = 'eggs') -> str:
    print("Annotations:", f.__annotations__)
    print("Arguments:", ham, eggs)
    return ham + ' and ' + eggs

f('spam')
Annotations: {'return': <class 'str'>, 'eggs': <class 'str'>, 'ham': <class 'str'>}
Arguments: spam eggs





'spam and eggs'

代码风格

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

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

  1. 使用4个空格来缩进,不要用tab。4个空格是在小的缩进(可以有更大的嵌套深度)和大的缩进(易读)之间的权衡。Tabs会引入混淆,不要使用
  2. 确保每行不超过79个字符,否则就要换行。这有助于用户使用小型显示器,并可以在较大的显示器上并排显示多个代码文件。
  3. 使用空行分开函数和类以及函数内部大的代码块
  4. 如果可能,将注释和代码放在一行
  5. 使用文本字符串docstrings
  6. 在操作符两侧及逗号commas后面使用空格,但不要在括号内侧使用,例如f(1, 2)
  7. 使你的类和函数命名风格一致,惯例是使用CameCase风格命名类,使用lower——case——with——underscores命名函数和方法
    保证让self作为第一个方法参数
  8. 如果你的代码用在国际环境,不要使用奇怪的编码。Python默认的UTF-8或者甚至ASCII可以工作在任何条件下
  9. 同样,不要在标识符中使用非ASCII字符,如果只有轻微的机会人们说不同的语言会读取或维护代码。

猜你喜欢

转载自blog.csdn.net/u010132497/article/details/80665372