1函数
1.1 定义函数
def <名称>(<形式参数>):
return <返回表达式>
①<形式参数>是以逗号分隔命名的列表。
②第二行必须缩进。
③返回时表达值不会立即计算,在最终调用函数才计算。
④纯函数(最好)可以作为定义其他函数的构建块
def sum_squares ( x , y ):
return add ( square ( x ), square ( y ))
函数的名称会重复两次,一次在定义框架中,另一次作为函数本身被调用的一部分。
1.2 函数赋值
def语句和赋值语句都将名称绑定到值,并且任何现有的绑定都会丢失。
例如,下面的g首先指的是无参数的函数,然后是数字,然后是拥有两个参数的新函数。
>>> def g():
return 1
>>> g()
1
>>> g = 2
>>> g
2
>>> def g(h, i):
return h + i
>>> g(1, 2)
3
1.3 自定义函数
新的framework,不再是global framework。该framework只能由该函数访问。
①整个函数的def语句是在一个步骤中处理的。
②函数只有在调用的时候才执行,而不是定义的时候
③里面的形参是在新的framework下。在全局中定义的参数才在global framework。函数名在global framework
④每次调用函数时都会引入一个新的本地framework,调用完framework就删掉,即使同一函数被调用两次也是如此。
⑤调用函数时输入的第一个值,跟定义函数时第一个形参绑定。
# eg.
def improve(update, close, guess=1):...
improve(sqrt_update, sqrt_close)
# 在这里,sqrt_update()(值)与update(名称)绑定
⑥不同本地框架中x的绑定是不相关的。计算模型经过精心设计以确保这种独立性。
⑦函数体内的赋值语句不能影响全局框架。函数只能操纵其本地环境。
⑧return表达式的值是正在应用的函数的返回值。
1.4 命名规则
①函数名称小写,单词间“_”连接
②不用print add max命名
③当作用明显时,可以使用单字母参数名称,但应避免使用“l”(小写 ell)、“O”(大写 oh)或“I”(大写 i),以避免与数字混淆
④重要tips!!!学会拆分功能!
每个功能都应该只有一项工作。该工作应该可以通过一个简短的名称来识别,并可以用一行文本来描述。依次执行多项作业的函数应划分为多个函数。
一个例子
def pressure(v, t, n=6.022e23):
"""Compute the pressure in pascals of an ideal gas.
v -- volume of gas, in cubic meters
t -- absolute temperature in degrees kelvin
n -- particles of gas (default: one mole)
"""
k = 1.38e-23 # Boltzmann's constant
return n * k * t / v
2 控制
2.1 条件语句
···
if <表达式>:
<套件>
elif <表达式>:
<套件>
else:
<套件>
···
布尔值
True 真值
False 假值:0、None、和布尔值False
布尔值内置比较操作符>、<、>=、<=、==、!=
**注意!赋值 ( = ) 与相等比较 ( == )
比较语句:
x > 0 and sqrt(x) > 10
n == 0 or 1/n != 0.0
## 2.2 迭代(重复)
#### while
```python
while k < n:
pred, curr = curr, pred + curr
k = k + 1
不终止的while语句称为无限循环。按<Control>-C强制 Python 停止循环。
2.3测试
断言
assert fib ( 8 ) == 13, 'The 8th Fibonacci number should be 13'
def fib_test():
#......
assert fib(2) == 1, 'The 2nd Fibonacci number should be 1'
assert fib(3) == 1, 'The 3rd Fibonacci number should be 1'
assert fib(50) == 7778742049, 'Error at the 50th Fibonacci number'
断言的表达式的计算结果为真值时,执行断言语句不起作用。当它是假值时,断言会导致错误并停止执行。
文档测试
可以将简单的测试直接放置在函数的文档字符串中。
文档字符串的第一行应包含函数的单行描述,后跟一个空行。随后可能会详细描述参数和行为。此外,文档字符串可能包括调用该函数的示例交互式会话:
>>> def sum_naturals(n):
"""Return the sum of the first n natural numbers.
>>> sum_naturals(10)
55
>>> sum_naturals(100)
5050
"""
total, k = 0, 1
while k <= n:
total, k = total + k, k + 1
return total
然后,可以通过doctest 模块验证交互。
(全局函数版)
>>> from doctest import testmod
>>> testmod()
TestResults(failed=0, attempted=2)
(单个函数版)
第一个参数是要测试的函数。第二个应该始终是表达式 globals()的结果,这是一个返回全局环境的内置函数。第三个参数为True表示我们想要“详细”输出:所有运行的测试的目录。
>>> from doctest import run_docstring_examples
>>> run_docstring_examples(sum_naturals, globals(), True)
Finding tests in NoName
Trying:
sum_naturals(10)
Expecting:
55
ok
Trying:
sum_naturals(100)
Expecting:
5050
ok
在文件中编写 Python 时,可以通过使用 doctest 命令行选项启动 Python 来运行文件中的所有 doctest:
python3 -m doctest <python_source_file>
3 高阶函数
3.1嵌套函数
def sqrt(a):
def sqrt_update(x):
return average(x, a/x)
def sqrt_close(x):
return approx_eq(x * x, a)
return improve(sqrt_update, sqrt_close)
在这里,framework的嵌套关系是:
即,层层嵌套关系
3.2用于返回值的函数
def compose1(f, g):
def h(x):
return f(g(x))
return h
3.3lambda表达式
在 Python 中,我们可以使用lambda 表达式动态创建函数值,该表达式的计算结果为未命名函数。
特点:
①计算结果是一个函数!未命名函数!
②此函数返回一个表达式。
③不允许赋值和控制语句。
④lambda的简写:左边是输入的值,右边是有返回值的函数的返回值表达式
compose1 = lambda f , g : lambda x : f ( g ( x ))
上式就等价于以下的example1
# example1
def compose1(f, g):
return lambda x: f(g(x))
## take x and return f(g(x))
# example2
>>> s = lambda x: x * x
>>> s
<function <lambda> at 0xf3f490>
>>> s(12)
144
# example3
def compose1(f, g):
return lambda x: f(g(x))
f = compose1(lambda x: x * x, lambda y: y + 1)
result = f(12)
result
#output:169 即(12+1)*(12+1)
# example4
def inverse(f): ## 用lambda多简洁!
"""Return a function g(y) that returns x such that f(x) == y.
>>> sqrt = inverse(square)
>>> sqrt(16)
4
"""
return lambda y: search(lambda x: f(x) == y)
思考:用lambda和不用的区别是?
square = x * x
square = lambda x: x * x
3.4 函数装饰器
@trace是注释,会影响def的执行规则。
>>> def trace(fn):
def wrapped(x):
print('-> ', fn, '(', x, ')') ## 对比下面
return fn(x)
return wrapped
>>> @trace
def triple(x):
return 3 * x
>>> triple(12)
-> <function triple at 0x102a39848> ( 12 ) ## 看这里!它已经有了trace函数返回值的属性了!
36
在上面的例子里,名称triple不与该函数绑定,而是绑定到调用trace函数返回函数值的新定义的triple上。等价于:
>>> def triple(x):
return 3 * x
>>> triple = trace(triple)
>>> triple
<function trace.<locals>.wrapped at 0x000002B4E64CD3F0>