目录
1. 懒惰
斐波那契数 (一种数列,其中每个数都是前两个数的和)
fibs = [0, 1]
for i in range(8):
fibs.append(fibs[-2] + fibs[-1])
>>> fibs
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
fibs = [0, 1]
num = int(input('How many Fibonacci numbers do you want? '))
for i in range(num-2):
fibs.append(fibs[-2] + fibs[-1])
print(fibs)
创建一个名为fibs 的函数,并在需要计算斐波那契数时调用它。如果需要在多个地方计算斐波那契数,这样做可节省很多精力。
num = input('How many numbers do you want? ')
print(fibs(num))
2. 抽象和结构
下载网页并计算使用频率
page = download_page()
freqs = compute_frequencies(page)
for word, freq in freqs:
print(word, freq)
3. 自定义函数
要判断某个对象是否可调用,可使用内置函数callable
>>> import math
>>> x = 1
>>> y = math.sqrt
>>> callable(x)
False
>>> callable(y)
True
使用def 定义函数。
def hello(name):
return 'Hello, ' + name + '!'
>>> print(hello('world'))
Hello, world!
>>> print(hello('Gumby'))
Hello, Gumby!
编写一个函数,返回一个由斐波那契数组成的列表。
def fibs(num):
result = [0, 1]
for i in range(num-2):
result.append(result[-2] + result[-1])
return result
>>> fibs(10)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
>>> fibs(15)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377]
3.1 给函数编写文档
可添加注释(以#打头的内容)。
也可以添加独立的字符串。如def 语句后面(以及模块和类的开头)。放在函数开头的字符串称为文档字符串 (docstring),将作为函数的一部分存储起来。
def square(x):
'Calculates the square of the number x.'
return x * x
# 访问文档字符串
# __doc__ 是函数的一个属性。
>>> square.__doc__
'Calculates the square of the number x.'
# 用help获取函数信息
>>> help(square)
Help on function square in module __main__:
square(x)
Calculates the square of the number x.
3.2 不是函数的函数
在Python中,函数就是函数,即使它严格来说并非函数。什么都不返回的函数不包含return 语句,或者包含return 语句,但没有在return 后面指定值。
def test():
print('This is printed')
return
print('This is not')
# 这里使用return 语句只是为了结束函数。
>>> x = test()
This is printed
# 跳过了第二条print语句。(这有点像在循环中使用break ,但跳出的是函数。)
# 既然test什么都不返回,那么x向的是什么,什么都没有
>>> x
>>>
>>> print(x)
None
所有的函数都返回值。如果你没有告诉它们该返回什么,将返回None 。
如果在if 之类的语句中返回值,务必确保其他分支也返回值,以免在调用者期望函数返回一个序列时(举个例子),不小心返回了None 。
4. 参数魔法
4.1 值从哪里来
在def 语句中,位于函数名后面的变量通常称为形参 ,而调用函数时提供的值称为实参 。
4.2 能修改参数吗
参数不过是变量而已,行为与你预期的完全相同。在函数内部给参数赋值对外部没有任何影响。
在try_to_change内,将新值赋给了参数n ,这对变量name 没有影响。说到底,这是一个完全不同的变量。
>>> def try_to_change(n):
n = 'Mr. Gumby'
>>> name = 'Mrs. Entity'
>>> try_to_change(name)
>>> name
'Mrs. Entity'
# 传递并修改参数的效果类似于下面这样:
>>> name = 'Mrs. Entity'
>>> n = name # 与传递参数的效果几乎相同
>>> n = 'Mr. Gumby' # 这是在函数内进行的
>>> name
'Mrs. Entity'
变量n 变了,但变量name 没变。同样,在函数内部重新关联参数(即给它赋值)时,函数外部的变量不受影响。
参数存储在局部作用域内。
字符串(以及数和元组)是不可变的(immutable),这意味着你不能修改它们(即只能替换为新值)。但如果参数为可变的数据结构(如列表)呢?
>>> def change(n):
n[0] = 'Mr. Gumby'
>>> names = ['Mrs. Entity', 'Mrs. Thing']
>>> change(names)
>>> names
['Mr. Gumby', 'Mrs. Thing']
4.3 关键字参数和默认值
使用名称指定的参数称为关键字参数 ,主要优点是有助于澄清各个参数的作用。也可以指定默认值。
def hello_1(greeting, name):
print('{}, {}!'.format(greeting, name))
def hello_2(name, greeting):
print('{}, {}!'.format(name, greeting))
>>> hello_1('Hello', 'world')
Hello, world!
>>> hello_2('Hello', 'world')
Hello, world!
def hello_3(greeting='Hello', name='world'):
print('{}, {}!'.format(greeting, name))
# 给参数指定默认值后,调用函数时可不提供它!
# 可以根据需要,一个参数值也不提供、提供部分参数值或提供全部参数值。
>>> hello_3()
Hello, world!
>>> hello_3('Greetings')
Greetings, world!
>>> hello_3('Greetings', 'universe')
Greetings, universe!
4.4 收集参数
参数前面的星号将提供的所有值都放在一个元组中,也就是将这些值收集起来。
def print_params(*params):
print(params)
>>> print_params('Testing')
('Testing',)
>>> print_params(1, 2, 3)
(1, 2, 3)
带星号的参数也可放在其他位置(而不是最后)
>>> 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
>>> in_the_middle(1, 2, 3, 4, 5, 7)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: in_the_middle() missing 1 required keyword-only argument: 'z'
星号不会收集关键字参数。
>>> print_params_2('Hmm...', something=42)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: print_params_2() got an unexpected keyword argument 'something'
要收集关键字参数,可使用两个星号。
>>> 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
()
{}
4.5 分配参数
只有在定义函数(允许可变数量的参数)或 调用函数时(拆分字典或序列)使用,星号才能发挥作用。
>>> def with_stars(**kwds):
... print(kwds['name'], 'is', kwds['age'], 'years old')
...
>>> def without_stars(kwds):
... print(kwds['name'], 'is', kwds['age'], 'years old')
...
>>> args = {'name': 'Mr. Gumby', 'age': 42}
>>> with_stars(**args)
Mr. Gumby is 42 years old
>>> without_stars(args)
Mr. Gumby is 42 years old
5. 作用域
变量存储在作用域(也叫命名空间 )中。在Python中,作用域分两大类:全局作用域和局部作用域。作用域可以嵌套。
6. 递归
函数可调用自身,这称为递归 。可使用递归完成的任何任务都可使用循环来完成,但有时使用递归函数的可读性更高。