Python:4. More Control Flow Tools(更多控制流工具)

文章介绍了Python中的控制流工具,包括if语句、for循环、range函数以及函数定义。特别提到了match语句的新特性,用于模式匹配。此外,还强调了函数的使用,包括默认参数、关键字参数和可变参数。最后,讨论了编码风格的重要性,推荐遵循PEP8规范。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

4. 更多控制流工具

除了刚才介绍的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 if”的缩写,很有用 以避免过度缩进。一。。。。。。。。。序列是其他语言中的 OR 语句的替代品。elififelifelifswitchcase

如果要将同一值与多个常量进行比较,或者检查特定类型或 属性,您可能还会发现该语句很有用。欲了解更多信息 详细信息请参阅匹配语句。match

4.2. 声明for
Python 中的 for 语句与你可能使用的语句略有不同 到 C 或 Pascal。而不是总是迭代算术级数 数字(如在 Pascal 中),或让用户能够定义两者 迭代步骤和停止条件(如C),Python的语句 循环访问任何序列(列表或字符串)的项,顺序为 它们按顺序显示。例如(没有双关语):for

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

cat 3
window 6
defenestrate 12

在循环访问同一集合时修改集合的代码可以 要做对很棘手。相反,循环通常更直接 或创建新集合:

# Create a sample collection
users = {'Hans': 'active', 'Éléonore': 'inactive', '景太郎': 'active'}

# Strategy:  Iterate over a copy
for user, status in users.copy().items():
    if status == 'inactive':
        del users[user]

# Strategy:  Create a new collection
active_users = {}
for user, status in users.items():
    if status == 'active':
        active_users[user] = status

4.3. 范围() 函数
如果您确实需要迭代数字序列,内置函数 range() 会派上用场。它生成算术级数:

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

0
1
2
3
4

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

>>>
list(range(5, 10))
[5, 6, 7, 8, 9]

list(range(0, 10, 3))
[0, 3, 6, 9]

list(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(10)
range(0, 10)

在许多方面,range() 返回的对象的行为就像一个列表, 但事实并非如此。它是一个返回 当您迭代它时所需的序列,但它并没有真正使 列表,从而节省空间。

我们说这样的对象是可迭代的,也就是说,适合作为目标 函数和构造,期望从中可以得到的东西 获取连续物品,直到供应耗尽。我们已经看到 for 语句就是这样的构造,而函数的示例 需要迭代对象的是 sum():

>>>
sum(range(4))  # 0 + 1 + 2 + 3
6

稍后我们将看到更多返回可迭代对象并将可迭代对象作为 参数。在数据结构一章中,我们将更详细地讨论 list()。

4.4. 和语句,以及循环上的子句breakcontinueelse
与 C 语言中一样,break 语句脱离了最内层的封闭 for 或 while 循环。

循环语句可以有一个子句;当循环时执行 通过耗尽可迭代对象(带 for)或当 条件变为假(使用 while),但当循环为 由中断语句终止。例如 以下循环,用于搜索质数:else

>>>
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
(是的,这是正确的代码。仔细看:该条款属于 for 循环,而不是 if 语句。else

当与循环一起使用时,该子句与 try 语句的子句比与 if 语句的子句有更多的共同点:try 语句的子句运行 当没有发生异常时,循环的子句在未发生时运行。有关语句和异常的详细信息,请参阅处理异常。elseelseelseelsebreaktry

继续语句,也是从 C 借来的,继续下一个 循环迭代:

>>>
for num in range(2, 10):
    if num % 2 == 0:
        print("Found an even number", num)
        continue
    print("Found an odd number", num)

Found an even number 2
Found an odd number 3
Found an even number 4
Found an odd number 5
Found an even number 6
Found an odd number 7
Found an even number 8
Found an odd number 9

4.5. 声明pass
pass 语句不执行任何操作。当语句 语法上是必需的,但程序不需要任何操作。例如:

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

这通常用于创建最小类:

>>>
class MyEmptyClass:
    pass

另一个地方通行证可以用作功能或 处理新代码时的条件体,让您继续思考 在更抽象的层面上。被静默忽略:pass

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

4.6. 声明match
match 语句采用表达式并将其值与连续 模式作为一个或多个案例块给出。这是表面上的 类似于 C、Java 或 JavaScript 中的 switch 语句(以及许多 其他语言),但它更类似于模式匹配 像 Rust 或 Haskell 这样的语言。仅匹配的第一个模式 执行,它还可以提取组件(序列元素) 或对象属性)从值转换为变量。

最简单的形式是将主题值与一个或多个文本进行比较:

def http_error(status):
    match status:
        case 400:
            return "Bad request"
        case 404:
            return "Not found"
        case 418:
            return "I'm a teapot"
        case _:
            return "Something's wrong with the internet"

注意最后一个块:“变量名”充当通配符和 永远不会失败匹配。如果没有大小写匹配,则不执行任何分支。_

您可以使用 (“or”) 将多个文本组合到单个模式中:|

case 401 | 403 | 404:
    return "Not allowed"

模式可以看起来像解包分配,并可用于绑定 变量:

# point is an (x, y) tuple
match point:
    case (0, 0):
        print("Origin")
    case (0, y):
        print(f"Y={y}")
    case (x, 0):
        print(f"X={x}")
    case (x, y):
        print(f"X={x}, Y={y}")
    case _:
        raise ValueError("Not a point")

仔细研究那个!第一个模式有两个文字,并且可以 被认为是上面显示的文字模式的扩展。但 接下来的两个模式组合了一个文本和一个变量,并且 变量绑定来自主题 () 的值。第四 模式捕获两个值,这使得它在概念上类似于 解包作业 .point(x, y) = point

如果使用类来构建数据 您可以使用类名后跟类似于 构造函数,但能够将属性捕获到变量中:

class Point:
    x: int
    y: int

def where_is(point):
    match point:
        case Point(x=0, y=0):
            print("Origin")
        case Point(x=0, y=y):
            print(f"Y={y}")
        case Point(x=x, y=0):
            print(f"X={x}")
        case Point():
            print("Somewhere else")
        case _:
            print("Not a point")

您可以将位置参数与一些内置类一起使用,这些类提供 对其属性(例如数据类)进行排序。您还可以定义特定的 通过设置特殊属性在模式中的位置 属性。如果设置为 (“x”、“y”),则以下模式均为 等效(并且全部将属性绑定到变量):__match_args__yvar

Point(1, var)
Point(1, y=var)
Point(x=1, y=var)
Point(y=var, x=1)

阅读模式的推荐方法是将它们视为您的扩展形式 将放在赋值的左侧,以了解哪些变量将设置为 什么。 只有独立名称(如上所述)由 match 语句分配给。 虚线名称(如)、属性名称(及以上)或类名称 (像上面一样由它们旁边的“(…)”识别)永远不会被分配到。varfoo.barx=y=Point

模式可以任意嵌套。例如,如果我们有一个短 点列表,我们可以像这样匹配它:

match points:
    case []:
        print("No points")
    case [Point(0, 0)]:
        print("The origin")
    case [Point(x, y)]:
        print(f"Single point {x}, {y}")
    case [Point(0, y1), Point(0, y2)]:
        print(f"Two on the Y axis at {y1}, {y2}")
    case _:
        print("Something else")

我们可以在模式中添加一个子句,称为“守卫”。如果 守卫是假的,继续尝试下一个案例块。注意 该值捕获发生在评估防护之前:ifmatch

match point:
    case Point(x, y) if x == y:
        print(f"Y=X at {x}")
    case Point(x, y):
        print(f"Not on the diagonal")

该声明的其他几个关键特征:

与解包作业一样,元组和列表模式恰好具有 相同的含义,实际上匹配任意序列。重要 例外情况是它们不匹配迭代器或字符串。

Sequence patterns support extended unpacking: and work similar to unpacking assignments. The name after may also be , so matches a sequence of at least two items without binding the remaining items.[x, y, *rest](x, y, *rest)*_(x, y, *_)

Mapping patterns: captures the and values from a dictionary. Unlike sequence patterns, extra keys are ignored. An unpacking like is also supported. (But would be redundant, so it is not allowed.){"bandwidth": b, "latency": l}"bandwidth""latency"**rest**_

Subpatterns may be captured using the keyword:as

case (Point(x1, y1), Point(x2, y2) as p2): ...
will capture the second element of the input as (as long as the input is a sequence of two points)p2

Most literals are compared by equality, however the singletons , and are compared by identity.TrueFalseNone

Patterns may use named constants. These must be dotted names to prevent them from being interpreted as capture variable:

from enum import Enum
class Color(Enum):
    RED = 'red'
    GREEN = 'green'
    BLUE = 'blue'

color = Color(input("Enter your choice of 'red', 'blue' or 'green': "))

match color:
    case Color.RED:
        print("I see red!")
    case Color.GREEN:
        print("Grass is green")
    case Color.BLUE:
        print("I'm feeling the blues :(")

有关更详细的解释和其他示例,您可以查看以教程格式编写的 PEP 636。

4.7. 定义函数
我们可以创建一个函数,将斐波那契级数写入任意 边界:

>>>
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 引入了函数定义。它必须是 后跟函数名称和形式参数的括号列表。 构成函数主体的语句从下一行开始,并且 必须缩进。

函数体的第一个语句可以选择是字符串文本; 此字符串文本是函数的文档字符串或文档字符串。 (有关文档字符串的更多信息,请参阅文档字符串部分。 有些工具使用文档字符串自动生成在线或打印 文档,或让用户以交互方式浏览代码;很好 练习在你编写的代码中包含文档字符串,所以养成习惯。

函数的执行引入了用于本地的新符号表 函数的变量。更准确地说,所有变量赋值 函数将值存储在本地符号表中;而变量引用 首先查看本地符号表,然后查看本地符号表 将函数括起来,然后在全局符号表中,最后在表中 的内置名称。因此,全局变量和封闭函数的变量 不能在函数中直接赋值(除非,对于全局 变量,在全局语句中命名,或者,用于封闭变量 函数,在非本地语句中命名),尽管它们可能是 引用。

函数调用的实际参数(参数)在本地引入 被调用函数时被调用函数的符号表;因此,参数是 使用按值调用传递(其中值始终是对象引用, 而不是对象的值)。1 当一个函数调用另一个函数时, 或者递归地称自己为一个新的 将为该调用创建本地符号表。

函数定义将函数名称与 中的函数对象相关联 当前符号表。解释器识别 该名称作为用户定义的函数。其他名称也可以指向相同的名称 函数对象,也可用于访问函数:

>>>
fib
<function fib at 10042ed0>
f = fib
f(100)
0 1 1 2 3 5 8 13 21 34 55 89

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

>>>
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 语句返回函数中的值。 没有表达式参数返回 .脱落 函数的结尾也返回 。returnNoneNone

该语句调用列表对象的方法。方法是一个“属于”对象的函数,被命名为 ,其中是某个对象(这可能是一个表达式), 和 是由对象的类型定义的方法的名称。 不同的类型定义不同的方法。不同类型的方法可能有 相同的名称而不会引起歧义。(可以定义自己的 对象类型和方法,使用类,请参阅类) 示例中所示的方法是为列表对象定义的;它 在列表末尾添加一个新元素。在此示例中,它等效于 ,但效率更高。result.append(a)resultobj.methodnameobjmethodnameappend()result = result + [a]

4.8. 更多关于定义函数的信息
也可以定义具有可变参数数量的函数。 有三种形式,可以组合。

4.8.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

重要警告:默认值仅计算一次。这使得 默认值为可变对象(如列表、字典或 大多数类的实例。例如,以下函数累积 在后续调用中传递给它的参数:

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.8.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, "!")

接受一个必需参数 () 和三个可选参数 (、 和 )。可以在任何 以下方式:voltagestateactiontype

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

在函数调用中,关键字参数必须跟在位置参数后面。 传递的所有关键字参数必须与其中一个参数匹配 被函数接受(例如 不是函数的有效参数),它们的顺序并不重要。这还包括 非可选参数(例如 也是有效的)。 任何参数都不能多次接收值。 下面是由于此限制而失败的示例:actorparrotparrot(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 argument 'a'

当表单的最终形式参数存在时,它会收到一个 字典(请参阅映射类型 — 字典),包含除 对应于形式参数的参数。这可以与正式的 表单的参数(在下一小节中描述),其中 接收包含位置的元组 形式参数列表之外的参数。( 必须发生 之前。例如,如果我们定义一个这样的函数:namenamenamename

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.8.3. 特殊参数
默认情况下,参数可以通过位置传递给 Python 函数 或按关键字明确。为了可读性和性能,有必要 限制参数的传递方式,以便开发人员只需查看 在函数定义中确定项目是否按位置传递,由 位置或关键字,或按关键字。

函数定义可能如下所示:

def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
      -----------    ----------     ----------
        |             |                  |
        |        Positional or keyword   |
        |                                - Keyword only
         -- Positional only

其中 和 是可选的。如果使用,这些符号表示 参数通过如何将参数传递给函数: 仅位置、位置或关键字和仅关键字。关键字参数 也称为命名参数。/*

4.8.3.1. 位置或关键字参数
如果函数定义中不存在 并且不存在,则参数可以 按位置或关键字传递给函数。/*

4.8.3.2. 仅位置参数
更详细地查看这一点,可以标记某些参数 作为仅位置。如果仅定位,则参数的顺序很重要,并且 参数不能通过关键字传递。仅位置参数为 放在 (正斜杠)之前。用于逻辑 将仅位置参数与其余参数分开。 如果函数定义中没有,则没有仅位置 参数。///

后面的参数可以是位置或关键字或仅关键字。/

4.8.3.3. 仅关键字参数
要将参数标记为仅关键字,指示必须传递参数 通过关键字参数,在参数列表中将 an 放在第一个仅关键字参数之前。*

4.8.3.4. 函数示例
考虑以下示例函数定义,密切关注 标记和 :/*

>>>
def standard_arg(arg):
    print(arg)

def pos_only_arg(arg, /):
    print(arg)

def kwd_only_arg(*, arg):
    print(arg)

def combined_example(pos_only, /, standard, *, kwd_only):
    print(pos_only, standard, kwd_only)

第一个函数定义,最熟悉的形式, 对调用约定和参数没有限制 按位置或关键字传递:standard_arg

>>>
standard_arg(2)
2

standard_arg(arg=2)
2

第二个功能仅限于使用位置 函数定义中存在参数:pos_only_arg/

>>>
pos_only_arg(1)
1

pos_only_arg(arg=1)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg'

第三个函数只允许指示的关键字参数 在函数定义中通过 a:kwd_only_args*

>>>
kwd_only_arg(3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given

kwd_only_arg(arg=3)
3

最后一个在同一函数中使用所有三个调用约定 定义:

>>>
combined_example(1, 2, 3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: combined_example() takes 2 positional arguments but 3 were given

combined_example(1, 2, kwd_only=3)
1 2 3

combined_example(1, standard=2, kwd_only=3)
1 2 3

combined_example(pos_only=1, standard=2, kwd_only=3)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: combined_example() got some positional-only arguments passed as keyword arguments: 'pos_only'

最后,考虑这个函数定义,它在位置参数之间有潜在的冲突,并且具有以下键:name**kwdsname

def foo(name, **kwds):
return ‘name’ in kwds
没有可能的调用会使其返回,因为关键字将始终绑定到第一个参数。例如:True’name’

>>>
foo(1, **{'name': 2})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: foo() got multiple values for argument 'name'
>>>

但是使用(仅位置参数),这是可能的,因为它允许作为位置参数和关键字参数中的键:/name’name’

>>>
def foo(name, /, **kwds):
    return 'name' in kwds

foo(1, **{'name': 2})
True

换句话说,仅位置参数的名称可以毫无歧义地使用。**kwds

4.8.3.5. 回顾
用例将确定在函数定义中使用哪些参数:

def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):

作为指导:

如果希望参数的名称不是 可供用户使用。当参数名称没有实际数时,这很有用 意思是,如果你想在函数时强制执行参数的顺序 被调用,或者如果你需要采取一些位置参数和任意 关键字。

当名称具有含义且函数定义为 通过明确名称或您想要阻止更容易理解 依赖于所传递参数位置的用户。

对于 API,请使用仅位置以防止中断 API 更改 如果将来修改了参数的名称。

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

def write_multiple_items(file, separator, *args):
    file.write(separator.join(args))

通常,这些可变参数将在形式列表中排在最后 参数,因为它们会收集所有剩余的输入参数 传递给函数。参数之后出现的任何形式参数都是“仅关键字”参数,这意味着它们只能用作 关键字而不是位置参数。*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.8.5. 解压缩参数列表
当参数已在列表或元组中时,会发生相反的情况 但需要为需要单独位置的函数调用解压缩 参数。例如,内置的 range() 函数需要单独的开始和停止参数。如果它们不能单独提供,请编写 使用 -运算符调用函数以将参数从列表中解压缩 或元组:*

>>>
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.8.6. 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.8.7. 文档字符串
以下是有关文档内容和格式的一些约定 字符串。

第一行应始终是对象的简短摘要 目的。为简洁起见,它不应显式声明对象的名称或类型, 由于这些可以通过其他方式获得(除非名称恰好是 描述函数操作的动词)。此行应以大写字母开头 字母并以句点结尾。

如果文档字符串中有更多行,则第二行应为 空白,在视觉上将摘要与描述的其余部分分开。这 以下行应该是描述对象调用的一个或多个段落 约定、副作用等。

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.

4.8.8. 函数注释
函数注释是完全可选的元数据 有关用户定义函数使用的类型的信息(有关详细信息,请参阅 PEP 3107 和 PEP 484)。

批注作为字典存储在函数的属性中,对 功能。参数注释由参数名称后面的冒号定义,后跟 通过计算到注释值的表达式。返回注释是 由参数之间的文本 定义,后跟表达式 列表和表示 def 语句结尾的冒号。这 以下示例有一个必需参数、一个可选参数和返回 值注释: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.9. 间奏曲:编码风格
现在你即将编写更长、更复杂的 Python 片段,它是一个 谈论编码风格的好时机。大多数语言都可以编写(或更多) 简洁,格式)不同风格;有些比其他的更具可读性。 让其他人轻松阅读您的代码始终是一个好主意,并且采用 一个好的编码风格对此有很大帮助。

对于 Python 来说,PEP 8 已经成为大多数项目遵循的风格指南; 它促进了非常可读和赏心悦目的编码风格。每条蟒蛇 开发人员应该在某个时候阅读它;以下是最重要的一点 为您提取:

使用 4 空格缩进,不使用制表符。

4 个空格是小缩进之间的良好折衷(允许更大的 嵌套深度)和大缩进(更易于阅读)。选项卡介绍 混乱,最好被排除在外。

换行,使其不超过 79 个字符。

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

使用空行分隔函数和类,以及较大的 函数中的代码。

如果可能,将评论放在自己的一行上。

使用文档字符串。

在运算符周围和逗号后使用空格,但不要直接在内部使用 括号构造:。a = f(1, 2) + g(3, 4)

一致地命名您的类和函数;约定用于类和函数 和方法。始终用作第一个方法参数的名称 (有关类和方法的更多信息,请参阅类的初探)。UpperCamelCaselowercase_with_underscoresself

如果您的代码打算用于国际 环境。Python 的默认值、UTF-8 甚至普通 ASCII 在任何 箱。

同样,如果只有 说不同语言的人阅读或维持的可能性很小 代码。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值