Python基础 第6章 抽象

1. 引言及抽象和结构

生成斐波那契数列的代码如下:

1 fibs = [0, 1]
2 num = int(input('How many num you want:'))
3 for x in range(num-2):
4     fibs.append(fibs[-2] + fibs[-1])
5 print(fibs)
6 
7 结果:
8 How many num you want:8
9 [0, 1, 1, 2, 3, 5, 8, 13]

(1)让程序更抽象,可以让人更容易理解。

(2)函数,是结构化编程的核心。

 

2. 自定义函数

(1)使用def 语句定义函数,以实现结构化编程

 1 def fibs(num):
 2     fib_result = [0, 1]
 3     for x in range(num-2):
 4         fib_result.append(fib_result[-2] + fib_result[-1])
 5     return fib_result
 6 
 7 number = int(input('how many num do you want:'))
 8 print(fibs(number))
 9 
10 结果:
11 how many num do you want:12
12 [0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]

(2)可使用内置函数callable 判断某个对象是否可调用,返回布尔值True,False

(3)return 语句非常重要,用于从函数返回值。

  2.1 给函数编写文档

  给函数编写文档,便于其他人能够理解函数。放在函数开头的字符串称为文档字符串(独立的字符串),将作为函数的一部分被存储起来。

  可以使用 __doc__ 函数属性查询函数的解释,双下划线表示特殊属性。

1 def square(x):
2     'Caluates the square of the number x.'
3     return x * x
4 
5 print(square.__doc__)
6 
7 结果:
8 Caluates the square of the number x.

  2.2  所有函数都返回值,如果你没有告诉函数该返回什么,将返回None.

  ***2.3 不要让这种默认返回行带来麻烦。如果你在if 之类的语句中返回值,务必确保其他纷至也返回值,以免在调用者期望函数返回一个序列时,不小心返回了None。

 

3. 参数魔法

(1)能修改参数吗?

 1 #能修改参数吗?下面的例子不能
 2 def try_to_change(n):
 3     n = 'Mr.Gumby'
 4     return n
 5 
 6 name = 'Mrs.Entity'
 7 try_to_change(name)
 8 print(name)
 9 
10 结果:
11 Mrs.Entity
12 
13 上述修改并未成功,原因是,执行过程等同如下:
14 name = 'Mrs.Entity'
15 
16 n = name
17 n = 'Mr.Gumby'
18 try_to_change(name) 实际结果 改变的是n的值:'Mr.Gumby'
19 
20 name =  'Mrs.Entity' # name的指向并未发生改变
21 print(name):  'Mrs.Entity'

如果换成列表,则结果会不一样

#能修改参数吗?下面的例子能
def change(n):
    n[0] = 'Mr.Gumby'
#    return n

names = ['Mrs.Entity', 'Mrs.Thing']
change(names)
# change(names[:])
print(names)

结果:
['Mr.Gumby', 'Mrs.Thing']  #可以看出结果变了

原因,实际执行过程:
name 指向 列表['Mrs.Entity', 'Mrs.Thing'];
执行change(name)函数,n 指向 name,
n = name,n= ['Mrs.Entity', 'Mrs.Thing'],name = ['Mrs.Entity', 'Mrs.Thing']
n[0] = 'Mr.Gumby' 修改n列表的只,因为n和name实际指向同一个list,故即使是通过n修改的list,name输出的也是修改后的结果。
具体参看list修改。

   1)为何要修改参数

  因为在提高程序的抽象程度方面,使用函数来修改数据结构(如列表或字典)是一种不错的方式。

具体示例如下,需要认真理解:

 1 # 1. 定义一个初始化数据结构的函数
 2 def init(data):
 3     data['first'] = {}
 4     data['middle'] = {}
 5     data['last'] = {}
 6 
 7 # 2. 获取人员姓名的函数
 8 def lookup(data, lable, name):
 9     return data[lable].get(name)
10 
11 # 3. 存储人员姓名的函数
12 def store(data, full_name):    # 将参数data和full_name提供给这个函数,这些参数被设置为从外部获得的值
13     names = full_name.split()   # 通过拆分full_name创建一个名为names的列表
14     if len(names) == 2:         # 如果names的长度为2(只有名和姓),就将中间名设置为空字符串
15         names.insert(1, '')
16     labels = 'first', 'middle', 'last'  # 将这几个元素存储在元组lables中
17 
18     for lable, name in zip(labels, names):  # 使用zip函数将标签和对应的名字合并,以便对每个标签-名字对 执行如下操作
19         people = lookup(data, lable, name)  # 1)获取属于该标签和名字的列表
20         if people:
21             people.append(full_name)        # 2)将full_name附加到该列表末尾或插入一个新列表
22         else:
23             data[lable][name] = [full_name]
24 
25 mynames = {}
26 init(mynames)
27 store(mynames, 'Magnus Lie Hetland')
28 look_result = lookup(mynames, 'middle', 'Lie')
29 print(look_result)

  2)如果参数不可变

 

(2)关键字参数和默认值

 前述(1)中所使用的均是位置参数,因为这些参数的位置非常重要。

使用名称指定的参数,称之为关键字参数。主要有点是有助于澄清各个参数的作用。

通常,不应结合使用位置参数和关键字参数

 

(3)收集参数

参数前面加星号,可将提供的所有值都放在一个元组中,也即将这些值收集起来。

1 def print_params(*params):
2     print(params)
3 
4 print_params('Testing')
5 结果:
6 ('Testing',)
1 def print_params2(title, *params):
2     print(title, end=' ')
3     print(params)
4 
5 print_params2('numbers:', 1, 2, 3)
6 结果:
7 numbers: (1, 2, 3)

带星号(*)的参数也可以放在其它位置,而不一定是最后,但是该情况下必须使用名称指定后续参数

 1 def in_the_middle(x, *y, z):
 2     print(x, y, z)
 3 in_the_middle(1, 2, 3, 4, 5, 6)
 4 结果:
 5 TypeError: in_the_middle() missing 1 required keyword-only argument: 'z'
 6 
 7 # 根据报错提示,修改为如下:
 8 def in_the_middle(x, *y, z):
 9     print(x, y, z)
10 in_the_middle(1, 2, 3, 4, 5, z=6)
11 结果:
12 1 (2, 3, 4, 5) 6

星号(*)不会收集关键字参数,若要实现收集关键字参数,需使用两个星号(**)

 1 def print_params3(title, *pos, **params):
 2     print(title)
 3     print(pos)
 4     print(params)
 5 
 6 print_params3('dict:','a','b','c', x=1, y=2, z=3)
 7 
 8 结果:
 9 dict:
10 ('a', 'b', 'c')
11 {'x': 1, 'y': 2, 'z': 3}

 

(4)分配参数 - 不是很懂??? 

4.作用域

 

5. 递归

 

6. 本章小结

6.1 本章关键词

抽象:通过定义处理细节的函数,可让程序更抽象

函数定义:使用def语句定义函数。函数由语句块组成,它们从外部接受值(参数),并可能返回一个或多个值(计算结果)

参数:函数通过参数(调用函数时被设置的变量)接受所需的信息。在Python中,参数有两类:位置参数和关键字参数。通过给参数指定默认值,可使其变成可选的。

作用域:变量存储在作用域(命名空间)中。在Python中,作用域分两大类:全局作用域和局部作用域。作用域可以嵌套。

递归:函数可调用自身,称为递归。可使用递归完成的任何任务都可使用循环来完成,但有时使用递归函数的可读性更高。

函数式编程:Python提供了一些编程工具,其中包括lambda表达式以及函数map、filter和reduec。

 

6.2 新介绍函数

1 map(func, seq[, seq, ...])     #对序列中的所有元素执行函数
2 filter(func, seq)     #返回一个列表,其中包含对其执行函数时结果为真的所有元素
3 reduce(func, seq[, initial])     #等价于func(func(seq[0], seq[1], seq[2]), ...)
4 sum(seq)     #返回seq中所有元素的和
5 apply(func[, args[, kwargs]])     #调用函数(还提供需要传递给函数的参数)

 

posted @ 2019-08-31 22:02  ElonJiang  阅读(223)  评论(0编辑  收藏  举报