文档字符串
除了# 注释,有另一种编写注释的方式,就是添加独立的字符串。在有些地方,如def语句后面(以及模块和类的开头,),添加这样的字符串很有用。放在函数开头的字符串称为文档字符串(docstring),将作为函数的一部分存储起来。下面的代码演示了如何给函数添加文档字符串:
def square(x):
'Calculates the square of the number x.'
return x * x
可以像下面这样访问文档字符串:
>>> square.__doc__
'Calculates the square of the number x.'
收集参数
单星号 * (元组)
前面有星号的参数将被放在元组中。
因此星号意味着收集余下的位置参数。如果没有可供收集的参数,params将是一个空元组。
>>> print_params_2('Nothing:')
Nothing:
()
与赋值时一样,带星号的参数也可放在其他位置(而不是最后),但不同的是,在这种情况下你需要做些额外的工作:使用名称来指定后续参数。单星号不会收集关键字参数。
>>> def in_the_middle(x, *y, z):
... print(x, y, z)
...
>>> in_the_middle(1, 2, 3, 4, 5, z=7)
1 (2, 3, 4, 5) 7
双星号 ** (字典)
要收集关键字参数,可使用两个星号。
>>> def print_params_3(**params):
... print(params)
...
>>> print_params_3(x=1, y=2, z=3)
{'z': 3, 'x': 1, 'y': 2}
如你所见,这样得到的是一个字典而不是元组。可结合使用这些技术。
def print_params_4(x, y, z=3, *pospar, **keypar):
print(x, y, z)
print(pospar)
print(keypar)
其效果与预期的相同。
>>> print_params_4(1, 2, 3, 5, 6, 7, foo=1, bar=2)
1 2 3
(5, 6, 7)
{'foo': 1, 'bar': 2}
>>> print_params_4(1, 2)
1 2 3
()
{}
作用域
vars() 作用域
变量到底是什么呢?可将其视为指向值的名称。因此,执行赋值语句x = 1后,名称x指向值1。这几乎与使用字典时一样(字典中的键指向值),只是你使用的是“看不见”的字典。实际上,这种解释已经离真相不远。有一个名为vars的内置函数,它返回这个不可见的字典:
>>> x = 1
>>> scope = vars()
>>> scope['x']
1
>>> scope['x'] += 1
>>> x
2
遮盖和全局变量 globals()
读取全局变量的值通常不会有问题,但还是存在出现问题的可能性。如果有一个局部变量或参数与你要访问的全局变量同名,就无法直接访问全局变量,因为它被局部变量遮 住了。如果需要,可使用函数globals来访问全局变量。这个函数类似于vars,返回一个包含全局变量的字典。(locals返回一个包含局部变量的字典。)例如,在前面的示例中,如果有一个名为parameter的全局变量,就无法在函数combine中访问它,因为有一个与之同名的参数。然而,必要时可使用globals()[‘parameter’]来访问它。
>>> def combine(parameter):
... print(parameter + globals()['parameter'])
...
>>> parameter = 'berry'
>>> combine('Shrub')
Shrubberry
重新关联全局变量(使其指向新值)是另一码事。在函数内部给变量赋值时,该变量默认为局部变量,除非你明确地告诉Python它是全局变量。那么如何将这一点告知Python呢?
>>> x = 1
>>> def change_global():
... global x
... x = x + 1
...
>>> change_global()
>>> x
2
作用域嵌套
Python函数可以嵌套,即可将一个函数放在另一个函数内,如下所示:
def foo():
def bar():
print("Hello, world!")
bar()
嵌套通常用处不大,但有一个很突出的用途:使用一个函数来创建另一个函数。这意味着可像下面这样编写函数:
def multiplier(factor):
def multiplyByFactor(number):
return number * factor
return multiplyByFactor
在这里,一个函数位于另一个函数中,且外面的函数返回里面的函数。也就是返回一个函数,而不是调用它。重要的是,返回的函数能够访问其定义所在的作用域。换而言之,它携带着自己所在的环境(和相关的局部变量)!每当外部函数被调用时,都将重新定义内部的函数,而变量factor的值也可能不同。由于Python的嵌套作用域,可在内部函数中访问这个来自外部局部作用域(multiplier)的变量,如下所示:
>>> double = multiplier(2)
>>> double(5)
10
>>> triple = multiplier(3)
>>> triple(3)
9
>>> multiplier(5)(4)
20
像multiplyByFactor这样存储其所在作用域的函数称为闭包。
递归
非无穷递归函数将满足以下两个条件:
基线条件(针对最小的问题):满足这种条件时函数将直接返回一个值。
递归条件 包含一个或多个调用,这些调用旨在解决问题的一部分。
异常
try except raise
class MuffledCalculator:
muffled = False
def calc(self, expr):
try:
return eval(expr)
except ZeroDivisionError: ## 捕获后处理或继续引发异常
if self.muffled:
print('Division by zero is illegal')
else:
raise ## 捕获后仍引发异常
多个except:
except ZeroDivisionError:
print("The second number can not be Zero.")
except ValueError:
print("that was not a number.")
等价于用元组表示多个异常
except (ZeroDivisionError,ValueError):
print("all error info")
捕获导常对象本身并打印它
try:
x = int(input('Enter the first number: '))
y = int(input('Enter the second number: '))
print(x / y)
except (ZeroDivisionError, TypeError) as e:
print(e)
except子句也捕获两种异常,但由于你同时显式地捕获了对象本身,因此可将其打印出来,让用户知道发生了什么情况。
捕获所有
except:
print('Something wrong happened ...')
优化对异常对象进行检查
except Exception as e
无异常往下 使用else 子句
在有些情况下,在没有出现异常时执行一个代码块很有用。为此,可像条件语句和循环一样,给try/except语句添加一个else子句。
try:
print('A simple task')
except:
print('What? Something went wrong?')
else:
print('Ah ... It went as planned.')
如果你运行这些代码,输出将如下:
A simple task
Ah ... It went as planned.
通过使用else子句,可实现循环。
while True:
try:
x = int(input('Enter the first number: '))
y = int(input('Enter the second number: '))
value = x / y
print('x / y is', value)
except:
print('Invalid input. Please try again.')
else:
break
在这里,仅当没有引发异常时,才会跳出循环(这是由else子句中的break语句实现的)。换而言之,只要出现错误,程序就会要求用户提供新的输入。
优化
如果使用except Exception as e,
就可利用8.3.4节介绍的技巧在这个小型除法程序中打印更有用的错误消息。
while True:
try:
x = int(input('Enter the first number: '))
y = int(input('Enter the second number: '))
value = x / y
print('x / y is', value)
except Exception as e:
print('Invalid input:', e)
print('Please try again')
else:
break
finally
不管try 中的语句 是否引发异常,都将执行finally 中的语句
try:
1 / 0
except NameError:
print("Unknown variable")
else:
print("That went well!")
finally:
print("Cleaning up.")
No Leanote account? Sign up now.