浙大版PTA Python程序设计第六章题目详解及知识点分析
第六章 函数
-函数也是对象,下面程序可以正常运行吗?
def func(): #这里定义了一个名为 func 的函数,它
print("11",end=" ") #在被调用时打印字符串 "11",并且在末尾不换行。
print(id(func),type(func),func) #获取'func'的内存地址,类型,表现形式
(通常是内存地址和函数名)
分析:
会正常运行e.g.输出2352392832160 <class 'function'> <function func at 0x00000223B58A04A0>
函数本质上是对象,可以存储于数据结构(如列表字典)当中
函数对象,类型为 <class 'function'>
-形参和return语句都是可有可无的√
分析:在Python中定义函数时,不可省略的↓
def 关键字:定义函数时必须使用 def 关键字。
函数名称:紧跟在 def 关键字之后的是函数的名称,这是必须的,用于标识函数。
参数列表:即使函数不需要参数,也必须有一对空括号 (),用于定义参数列表。
函数体:至少需要一个冒号 : 和一个缩进的代码块,即函数体,即使它是空的。
例如,一个最简单的函数定义如下:
def foo():
…
这里…是ellipsis object(省略号对象)
形参:
在编程语言中,形参(Formal Parameter)是函数定义中用于接收传递给函数的值的变量。当函数被调用时,形参会被实际的参数(Argument)所替代,这些实际的参数是调用函数时提供的值。
例如,考虑以下Python函数定义:
def greet(name):
print("Hello, " + name + "!")
在这个函数中,name 就是一个形参。当你调用这个函数并传递一个实际的参数时,比如 greet("Alice"),name 形参就会被 "Alice" 这个实际参数所替代,并且函数会输出 "Hello, Alice!"。
-在一个函数中如局部变量和全局变量同名,则局部变量屏蔽全局变量
√
例如
x = 10 # 全局变量
def my_function():
x = 20 # 局部变量,屏蔽全局变量x
print("Inside the function, x =", x)
my_function() # 调用函数
print("Outside the function, x =", x)
#会输出↓
#Inside the function, x = 20
#Outside the function, x = 10
-area是tri模块中的一个函数,执行from tri import area 后,调用area函数应该使用____ 。
area()
分析:
当你使用 from tri import area 导入语句时,你直接将 area 函数从 tri 模块导入到当前的命名空间中。这意味着你可以直接使用 area() 来调用该函数,而不需要模块名称作为前缀。
如果我们用的是 import tri 那么调用area函数要用tri.area()例如
import tri
# 调用tri模块中的area函数
triangle_area = tri.area(base=10, height=5)
-函数可以改变哪种数据类型的实参?
int:整数 是不可变数据类型
string:字符串 是不可变数据类型
float:浮点数 是不可变数据类型
-list :列表是可变数据类型,函数内部可以改变原始的列表实参
-函数定义如下,程序输出是什么
def f1(a,b,c):
print(a+b)
nums=(1,2,3)
f1(nums)
分析:
f1 函数期望接收三个参数 a, b, c,但 f1(nums) 只传递了一个参数 nums;这里的nums相当于参数a。这会导致函数调用时参数数量不匹配(b和c没有)的错误
修正
def f1(a, b, c):
print(a + b)
nums = (1, 2, 3)
f1(*nums)
会输出3
①函数参数数量匹配:函数调用时传递的参数数量必须与函数定义时的参数数量匹配。
②拆包操作:使用 * 操作符可以将一个可迭代对象解包为单独的元素并传递给函数,确保参数数量匹配。
-下面程序运行结果是
def fun(x1,x2,x3,**x4):
print(x1,x2,x3,x4)
fun(x1=1,x2=22,x3=333,x4=4444)
分析:在函数定义中,**x4 会将所有多余的关键字参数以字典的形式捕获到 x4 中。如果你传递一个与 x4 同名的参数,那么它会被视为一个普通参数,而不是被捕获到 **x4 中。例如:
def fun(x1, x2, x3, **kwargs):
print(x1, x2, x3, kwargs)
fun(x1=1, x2=22, x3=333, extra=4444)
输出结果是
1 22 333 {'extra': 4444}
所以本题将输出
1 22 333 {'x4': 4444}
下列程序将输出什么
def scope():
n=4
m=5
print(m,n,end=' ')
n=5
t=8
scope()
print(n,t)
分析:
局部作用域:在函数内部定义的变量只在函数内部有效,不会影响全局作用域中的变量。
全局作用域:在函数外部定义的变量在整个程序中有效,除非在函数内部用 global 关键字声明,否则函数内部对同名变量的修改不会影响全局变量。
n = 5
t = 8
在全局作用域中,定义了两个变量 n 和 t,分别赋值为 5 和 8。
scope()
调用 scope 函数,执行函数内部的代码。
在 scope 函数的本地作用域中,定义了局部变量 n 和 m,分别赋值为 4 和 5。
print(m, n, end=' ') 输出局部变量 m 和 n 的值,即 5 和 4。输出 5 4 .
print(n, t)
打印全局作用域中的变量 n 和 t,它们的值依然是 5 和 8。输出 5 8。
所以最后输出5 4 5 8
关于输出5 4与5 8要不要换行:
print(m, n, end=' ') 输出 5 4,并在末尾添加一个空格,光标停在这一行的空格之后;紧接着上一步的输出,在同一行,print(n, t) 输出 5 8。
如果删去 print(m,n,end=' ')中的end=' '则会换行
输出
5 4
5 8
-下面程序运行结果是什么
def nprintf(message,n):
for i in range(n):
print(message,end=" ")
nprintf("a",3,)
nprintf(n=5,message="good")
分析:
函数实现功能是输出n个message
所以
nprintf("a",3,)
会输出
'a a a '(注意每个a后面都有一个空格)
nprintf(n=5,message="good")
会输出
'good good good good good '(每一个good后面也有一个空格)
所以原代码输出
'a a a good good good good good '
-下面程序输出是什么
lst=[(1,"one"),(2,"two"),(3,"three"),(4,"four")]
lst.sort(key=lambda x:x[1])
print(lst[3][1][2])
分析:
lst = [(1, "one"), (2, "two"), (3, "three"), (4, "four")] #定义了一个列表
lst.sort(key=lambda x: x[1]) #排序 sort 方法使用 key=lambda x: x[1] 对 lst 进行排序,这表示按照每个元组的第二个元素(即字符串部分)进行排序。
排序后 [(4, "four"), (1, "one"), (3, "three"), (2, "two")]
print(lst[3][1][2]) [3]访问列表第四个元素即(2, "two")
[1]访问该元组的第二个元素即two字符串
[2]访问字符串two的第三个元素 即o
所以输出o
-下列程序第四行输出什么
def perm(choice,selected=[]):
if len(choice)==1:
print("".join(selected+choice))
else:
for i in range(len(choice)):
t=choice[i]
choice.remove(t)
selected.append(t)
perm(choice,selected)
choice.insert(i,t)
selected.pop()
first=["1","2","3"]
perm(first,selected=[])
分析:
重点在于递归函数‘perm’的工作机制
基准:
当 choice 列表的长度为 1 时,将 selected 列表和 choice 列表连接起来,并打印结果。
递归:
遍历 choice 列表中的每个元素,将其移除并加入到 selected 列表中。
递归调用 perm 函数来处理剩余的 choice 列表。
递归调用结束后,将移除的元素重新插入到 choice 列表中的原位置,并从 selected 列表中移除
def perm(choice, selected=[]): # 定义一个函数 perm,接受两个参数 choice 和 selected,默认 selected 是一个空列表
if len(choice) == 1: # 如果 choice 的长度为 1
print("".join(selected + choice)) # 打印 selected 和 choice 的组合(将列表转换为字符串)
else: # 否则
for i in range(len(choice)): # 遍历 choice 列表的每个索引
t = choice[i] # 取出 choice 列表中索引为 i 的元素
choice.remove(t) # 从 choice 列表中移除该元素
selected.append(t) # 将该元素添加到 selected 列表中
perm(choice, selected) # 递归调用 perm 函数,传入修改后的 choice 和 selected 列表
choice.insert(i, t) # 在 choice 列表的索引 i 处插入元素 t(恢复原样)
selected.pop() # 从 selected 列表中移除最后一个元素(恢复原样)
# 例如调用 perm(["a", "b", "c"]) 将打印:
# abc
# acb
# bac
# bca
# cab
# cba
具体分析如下:
初始调用
first = ["1", "2", "3"]
perm(first, selected=[])
第一层递归:
选择 "1":
choice = ["2", "3"]
selected = ["1"]
perm(["2", "3"], ["1"])
选择 "2":
choice = ["1", "3"]
selected = ["2"]
perm(["1", "3"], ["2"])
选择 "3":
choice = ["1", "2"]
selected = ["3"]
perm(["1", "2"], ["3"])
第二层递归:
选择 "1" 后:
choice = ["3"]
selected = ["1", "2"]
perm(["3"], ["1", "2"])
输出 123
choice = ["2"]
selected = ["1", "3"]
perm(["2"], ["1", "3"])
输出 132
选择 "2" 后:
choice = ["3"]
selected = ["2", "1"]
perm(["3"], ["2", "1"])
输出 213
choice = ["1"]
selected = ["2", "3"]
perm(["1"], ["2", "3"])
输出 231
选择 "3" 后:
choice = ["2"]
selected = ["3", "1"]
perm(["2"], ["3", "1"])
输出 312
choice = ["1"]
selected = ["3", "2"]
perm(["1"], ["3", "2"])
输出 321
总结输出
最终,这段代码将会输出所有 ["1", "2", "3"] 的排列:
123
132
213
231
312
321
所以第四行输出231
-在Python中,函数是对象,可以像其他数据对象一样使用。下面程序的输出是
def func1():
print("11",end=" ")
def func2():
print("22",end=" ")
def func3():
print("33",end=" ")
funclist=[func1,func2,func3]
for func in funclist:
func()
分析:
def func1():
print("11", end=" ") # 定义函数 func1,打印 "11",输出后不换行,而是输出一个空格
def func2():
print("22", end=" ") # 定义函数 func2,打印 "22",输出后不换行,而是输出一个空格
def func3():
print("33", end=" ") # 定义函数 func3,打印 "33",输出后不换行,而是输出一个空格
funclist = [func1, func2, func3] # 创建一个函数列表 funclist,包含 func1, func2 和 func3
for func in funclist: # 遍历 funclist 列表中的每个函数
func() # 调用当前函数
使用 `for` 循环遍历 `funclist` 列表中的每个函数,并调用它们。
– 第一次循环时,`func` 是 `func1`,所以调用 `func1()`,输出 "11 "。
– 第二次循环时,`func` 是 `func2`,所以调用 `func2()`,输出 "22 "。
– 第三次循环时,`func` 是 `func3`,所以调用 `func3()`,输出 "33 "。
最终,代码的输出结果是:
```
11 22 33
```
每个函数的输出在一行上连续打印出来,因为我们使用了 `end=" "` 参数来防止打印后的换行。这展示了如何将函数视作一等公民(first-class citizens),即它们可以被赋值给变量、存储在数据结构中,并在需要时调用。
-下面程序的输出是
f = lambda p:p+5
t = lambda p:p*3
x=7
x=f(x)
x=t(x)
x=f(x)
print(x)
分析:
f = lambda p: p + 5 # 定义一个 lambda 函数 f,它接受一个参数 p,并返回 p + 5
t = lambda p: p * 3 # 定义另一个 lambda 函数 t,它接受一个参数 p,并返回 p * 3
x = 7 # 定义一个变量 x,初始值为 7
x = f(x) # 调用函数 f,将 x 的值(7)加 5,结果是 12,x 变为 12
x = t(x) # 调用函数 t,将 x 的值(12)乘以 3,结果是 36,x 变为 36
x = f(x) # 再次调用函数 f,将 x 的值(36)加 5,结果是 41,x 变为 41
print(x) # 打印 x 的最终值,输出 41
总结每一步的变化:
– 初始值:`x = 7`
– 第一次调用 `f(x)` 后:`x = 12`
– 第二次调用 `t(x)` 后:`x = 36`
– 第三次调用 `f(x)` 后:`x = 41`
最终输出结果是:
```
41
```
-下面程序的输出是
def factorial(n):
match n:
case 0 | 1:
return 1
case _:
return n * factorial(n - 1)
print(factorial(5))
分析:
def factorial(n):
match n: # 使用 match 语句对 n 进行模式匹配
case 0 | 1: # 如果 n 是 0 或 1
return 1 # 返回 1,这是阶乘的基例
case _: # 对于所有其他情况
return n * factorial(n - 1) # 返回 n 乘以 factorial(n - 1) 的结果,这是阶乘的递归定义
print(factorial(5)) # 调用 factorial(5),计算 5 的阶乘并打印结果
这段代码使用 引入的 `match` 语句来实现一个递归的阶乘函数。
逐步解析最后一行这个调用的执行过程:
– `factorial(5)` 触发 `case _`,返回 `5 * factorial(4)`
– `factorial(4)` 触发 `case _`,返回 `4 * factorial(3)`
– `factorial(3)` 触发 `case _`,返回 `3 * factorial(2)`
– `factorial(2)` 触发 `case _`,返回 `2 * factorial(1)`
– `factorial(1)` 触发 `case 0 | 1`,返回 `1`
通过递归调用,我们得到:
– `factorial(2)` = `2 * 1` = `2`
– `factorial(3)` = `3 * 2` = `6`
– `factorial(4)` = `4 * 6` = `24`
– `factorial(5)` = `5 * 24` = `120`
最终,代码的输出结果是:
```
120
```
-下列程序运行结果是
l=[1]
def scope1():
l.append(6)
print(*l)
scope1()
分析:
这段代码定义了一个列表 `l` 和一个函数 `scope1()`,然后调用了这个函数。逐行解析这段代码的作用及其输出结果,如下。
l = [1] # 定义一个列表 l,初始值为 [1]
def scope1():
l.append(6) # 向列表 l 中添加一个元素 6
print(*l) # 使用 * 运算符解包列表 l 的元素,并将其传递给 print 函数,打印列表中的所有元素,中间用空格分隔
scope1() # 调用 scope1 函数,执行上述操作
最终输出结果是:
```
16
```
在这段代码中,由于列表 `l` 是在全局作用域中定义的,函数 `scope1` 可以直接访问和修改全局变量 `l`。(即 Python 中列表作为可变对象的特性)
-下面程序运行结果是
a=10
def func():
global a
a=20
print(a,end=' ')
func()
print(a)
分析:
这段代码演示了如何在 Python 中使用 `global` 关键字来修改全局变量。让我们逐行解析代码的作用及其输出结果。
a = 10 # 定义一个全局变量 a,初始值为 10
def func():
global a # 声明 a 是一个全局变量
a = 20 # 将全局变量 a 的值修改为 20
print(a, end=' ') # 打印 a 的值(20),输出后不换行,而是输出一个空格
func() # 调用 func 函数,打印 20,光标停在同一行
print(a) # 打印全局变量 a 的值,此时 a 的值为 20
代码的执行过程如下:
1. 定义全局变量 `a` 并赋值为 `10`。
2. 定义函数 `func`,在函数内部使用 `global` 关键字声明并修改全局变量 `a` 的值为 `20`,然后打印 `20`。
3. 调用函数 `func`,打印出 `20`。
4. 在函数调用之后,再次打印全局变量 `a` 的值,此时 `a` 的值为 `20`。
最终输出结果是:
```
20 20
```
这段代码展示了如何在 Python 中使用 `global` 关键字来修改和访问全局变量。
-下面程序的运行结果是
b, c=2, 4
def g_func(d):
global a
a=d*c
g_func(b)
print(a)
分析:
b, c = 2, 4 # 定义两个全局变量 b 和 c,分别赋值为 2 和 4
def g_func(d):
global a # 声明 a 是一个全局变量
a = d * c # 计算 d 和全局变量 c 的乘积,并将结果赋值给全局变量 a
g_func(b) # 调用 g_func 函数,传入 b 的值(即 2)。因此,函数内执行 a = 2 * 4,a 被赋值为 8
print(a) # 打印全局变量 a 的值,输出 8
-下面程序的运行结果是
import math
def factors(x):
y=int(math.sqrt(x))
for i in range(2,y+1):
if (x%i ==0):
factors(x//i)
break
else:
print(x,end=' ')
return
factors(38)
分析:
这是一个找质因数(能整除给定正整数的质数)的程序
import math # 导入数学库,以便后面可以使用其中的数学函数
def factors(x): # 定义一个名为factors的函数,它接受一个参数x,表示要找质因数的数
y = int(math.sqrt(x)) # 计算x的平方根,并转换为整数,因为质因数不会超过其平方根
for i in range(2, y + 1): # 从2开始遍历到y+1(包括y),这个范围内的数都有可能是x的质因数
if x % i == 0: # 如果x可以被i整除,说明i是x的一个质因数
factors(x // i) # 递归调用factors函数,找出x // i的质因数
break # 找到一个质因数就可以停止了,使用break退出循环
else: # 如果x不能被当前的i整除,说明i不是x的质因数
print(x, end=' ') # 直接打印出x,end=' '是为了让打印出的数横向排列,而不是换行
return # 返回,结束函数
# 调用函数factors,传入参数38
factors(38)
#输出19
-下列程序运行结果是什么
def ins_sort_rec(seq, i):
if i == 0: return
ins_sort_rec(seq, i - 1)
j = i
while j > 0 and seq[j - 1] > seq[j]:
seq[j - 1], seq[j] = seq[j], seq[j - 1]
j -= 1
seq = [3,-6,79,45,8,12,6,8]
ins_sort_rec(seq, len(seq)-1)
print(seq[5])
分析:这是一段对列表序列排序的代码
def ins_sort_rec(seq, i): # 定义递归插入排序函数,参数为待排序序列seq和当前索引i
if i == 0: return # 基本情况:如果索引i为0,返回(递归结束条件)
ins_sort_rec(seq, i - 1) # 递归调用自身,将当前索引减1
j = i # 初始化j为当前索引i
while j > 0 and seq[j - 1] > seq[j]: # 循环条件:j大于0且前一个元素大于当前元素
seq[j - 1], seq[j] = seq[j], seq[j - 1] # 交换前一个元素和当前元素
j -= 1 # 将j减1,继续向前比较并交换
seq = [3, -6, 79, 45, 8, 12, 6, 8] # 定义待排序的序列
ins_sort_rec(seq, len(seq) - 1) # 调用递归插入排序函数,对序列进行排序,初始索引为最后一个元素的索引
print(seq[5]) # 输出排序后序列的第6个元素
#排完序seq=[-6, 3, 6, 8, 8, 12, 45, 79]所以第六个是12
-下面程序的运行结果是
def basic_lis(seq):
l=[1]*len(seq)
for cur ,val in enumerate(seq): #enumerate返回元素的"索引和值"
for pre in range(cur):
if seq[pre]<val:
l[cur]=max(l[cur],1+l[pre])
return max(l)
L=[49, 64, 17, 100, 86, 66, 78, 68, 87, 96, 19, 99, 35]
print(basic_lis(L))
分析:
def basic_lis(seq):
l = [1] * len(seq) # 初始化一个长度为seq的列表l,每个元素初始值为1,表示每个元素的最长递增子序列长度至少为1
for cur, val in enumerate(seq): # 枚举seq中的元素及其索引
for pre in range(cur): # 对当前元素之前的每个元素进行检查
if seq[pre] < val: # 如果前一个元素小于当前元素
l[cur] = max(l[cur], 1 + l[pre]) # 更新l[cur]为当前最大值,表示包括当前元素在内的最长递增子序列长度
return max(l) # 返回列表l中的最大值,即最长递增子序列的长度
L = [49, 64, 17, 100, 86, 66, 78, 68, 87, 96, 19, 99, 35] # 定义一个待处理的序列
print(basic_lis(L)) # 调用basic_lis函数并输出其结果
核心重点在下面这段代码的理解
for cur, val in enumerate(seq):
for pre in range(cur):
if seq[pre] < val:
l[cur] = max(l[cur], 1 + l[pre])
外层循环枚举 seq 中的每个元素及其索引。内层循环遍历当前元素之前的所有元素,检查是否存在递增关系(即 seq[pre] < val)。
如果存在递增关系,则更新 l[cur] 的值为 l[cur] 和 1 + l[pre] 中的较大值。这意味着如果当前元素 val 能接在前面的递增子序列后面,则更新当前元素的最长递增子序列长度。
对于给定的序列 L = [49, 64, 17, 100, 86, 66, 78, 68, 87, 96, 19, 99, 35],它的最长递增子序列是 [49, 64, 66, 68, 87, 96, 99],其长度为7。
-下面程序是冒泡排序的实现,请填空(答案中不要有空格)
def bubble(List):
for j in range(________,0,-1):
for i in range(0,j):
if List[i]>List[i+1]:List[i],List[i+1]=List[i+1],List[i]
return List
testlist = [49, 38, 65, 97, 76, 13, 27, 49]
print( bubble(testlist))
分析:由于range是左闭右开,而索引从0开始,所以最后一个元素索引是len(List)-1
def bubble(List):
for j in range(len(List) - 1, 0, -1): # 外层循环,从列表长度减1到1
for i in range(0, j): # 内层循环,从列表开头到j
if List[i] > List[i + 1]: # 如果当前元素大于下一个元素
List[i], List[i + 1] = List[i + 1], List[i] # 交换这两个元素
return List
testlist = [49, 38, 65, 97, 76, 13, 27, 49]
print(bubble(testlist)) # 输出排序后的列表
-下面程序是选择排序的实现,请填空(答案中不要有空格)
def selSort(nums):
n = len(nums)
for bottom in range(n-1):
mi = bottom
for i in range(_________, n):
if nums[i] < nums[mi]:
mi = i
nums[bottom], nums[mi] = nums[mi], nums[bottom]
return nums
numbers = [49, 38, 65, 97, 76, 13, 27, 49]
print(selSort(numbers))
分析:
在选择排序算法中,需要在未排序部分寻找最小值,并将其与当前循环位置的元素交换。
因此,内层循环的起始位置应该是 bottom + 1或者bottom。
def selSort(nums):
n = len(nums) # 计算列表的长度
for bottom in range(n - 1): # 外层循环,遍历列表的每一个元素,除了最后一个
mi = bottom # 假设当前索引bottom是最小值的索引
for i in range(bottom + 1, n): # 内层循环,从bottom + 1(或者bottom)开始,遍历剩余未排序的部分
if nums[i] < nums[mi]: # 如果找到一个更小的元素
mi = i # 更新最小值的索引为i
nums[bottom], nums[mi] = nums[mi], nums[bottom] # 交换当前元素和找到的最小元素
return nums # 返回排序后的列表
numbers = [49, 38, 65, 97, 76, 13, 27, 49]
print(selSort(numbers)) # 输出排序后的列表
未经允许 不得转载
作者:8 1 0