第18课 自定义函数的创建与调用

学习要点

(1)能够创建简单的自定义函数。

(2)掌握自定义函数的调用方法。

(3)理解函数的返回值。

(4)理解变量作用域、全局变量与局部变量。

对标内容

(1)能够创建简单的自定义函数,掌握自定义函数的调用。

(2)理解函数的返回值、变量作用域等概念。

函数的返回值

知识点详解

函数的返回值

函数不是直接显示输出的,它会处理一些数据并返回一个或一组值。

函数用return 语句将值返回调用函数的代码行,返回值能将程序大部分繁重的工作移交到函数中去完成,从而简化主程序。

下面是一个简单的程序,用于接收姓氏和名字,然后返回完整的人名信息。

def name(first_name,last_name):
    full_name=first_name+" "+last_name
    return full_name
print(name("zhangsan","san"))

运行结果:

zhangsan san

函数可以返问任何类型的值,包括字典、列表这样较复杂的数据结构。还是上面的例子,这次返回一个表示人的字典。

def name(first_name,last_name):
    full_name={"first":first_name,"last":last_name}
    return full_name
print(name("zhangsan","lisi"))

运行结果:

{'first': 'zhangsan', 'last': 'lisi'}

函数传递列表

传递列表在函数中很有用,列表中包含数字、名字甚至更复杂的对象,如下例所示。

def f(names):
    for i in names:
        print("Hello"+" "+i+"!!")
f(["zhangsan","lisi","wangwu"])

运行结果:

Hello zhangsan!!
Hello lisi!!
Hello wangwu!!

思考

(1)对于带返回值的函数,输入并运行以下代码。

def fact(n):
    factorial=1
    for counter in range(1,n+1):
        factorial*=counter
    return factorial
n=int(input('calculate n! Enter n=?'))
print(n,'!=',fact(n))

(2)对于带默认值的函数,输入并运行以下代码。

def rt1(a=3):
    for n in range(a):
        for m in range(n+1):
            print('*',end='')
        print()
rt1()
rt1(5)

易错点

(1)比对带返回值与不带返回值的自定义函数的差别,理解它们的含义。

(2)在函数中用return语句将值返回调用函数的代码行。

模拟考题

考题1 单选题

关于以下程序,下列表述中错误的一项是( )。

def demo(n):
    s=1
    for i in range(1,n):
        s*=i
    return s

A.demo(n)函数的功能是求n的阶乘 B. s是局部变量

C. n是形参 D. range())函数是Python内置函数

答案:A

解析∶demo(n)函数的功能是求阶乘,range(1,n)是从1循环到n-1。

考题2 单选题

运行以下程序,输出结果正确的是( )。

def demo(x):
    return x*2;
print(demo(demo(demo(1)))

A. 1 B. 2 C. 4 D. 8

答案:D

解析∶函数被调用3次,1乘以2,再乘以2,再乘以2,结果为8。

考题3 判断题

函数体中必须包含 return 语句。( )

答案:错误

解析∶自定义函数可以没有返回值。

全局变量和局部变量

知识点详解

一般定义在程序最开始处的变量称为全局变量,而在函数中定义的变量称为局部变量。

可以简单理解为,无缩进的为全局变量,有缩进的是局部变量。

全局变量的作用域是整个程序,而局部变量的作用域是函数内部。

当程序运行时,首先会找程序内部有没有局部变量,如果有,则调用;如果没有,才去调用全局变量。

name='zhang'    #全局变量
def f():
    name="li"    #局部变量
    print(name)
f()
print(name)        #打印全局变量name的值

运行结果:

li
zhang

调用f()函数,程序会先在函数内部找有没有name 这个变量,如果有,就会使用该name的值;而如果没有定义局部变量name,函数再去找全局变量name。

可以通过global关键字,通过局部变量修改全局变量的值,如下例所示。

name="zhang"    #定义全局变量
def f():
    global name    #在函数内部,通过global关键字,通过局部变量修改全局变量的值
    name="li"
    print(name)
f()                #打印局部变量name的值
print(name)        #打印全局变量name的值

运行结果:

li
li

在运行结果中可以明显看出,使用global关键字后,在定义局部变量的同时也修改了全局变量的值。

global与nonlocal的区别:

global关键字用来在定义局部变量的同时,修改全局变量的值;

nonlocal关键字用来在函数或局部作用域使用外层(非全局)变量。

def add():
    count=1
    def fun():
        nonlocal count
        print(count)
        count+=2
    return fun
a = add()
a()
a()

运行结果:

1
3

思考

(1)对于局部变量作用域,输入下列代码,并运行试试。

def f1():
    x=5
    y=6
    print(x+y)
def f2():   #改为(x)
    y=1
    print(x+y)    #出错!不能引用f1()中的x
f1()
f2()

调用f2()时出错了,处理办法有以下两种。

方法1:将 “def f2():” 改为 “def f2(x):”

方法2:将“x=5”从f1()中移出来,使x变为全局变量。

(2)如果在函数中定义的局部变量与全局变量同名,则调用函数时,局部变量屏蔽全局变量。输入下列代码,并运行试试。

x='outside'
y='global'
def f():
    x='inside'
    print(x)
    print(y)
f()
print(x)

运行结果:

inside
global
outside

易错点

(1)理解global与nonlocal关键字的区别和它们各自的用法。

(2)如果在函数中定义的局部变量与全局变量同名,则调用函数时,局部变量屏蔽全局变量。

模拟考题

考题1 单选题

运行以下程序,输出的结果是()。

x=1
def demo():
    global x
    x=2
    print(x)
demo()
print(x)

A. 1 B. 2 C. 1 D. 2

​ 1 1 2 2

答案:D

解析:Python中定义函数时,若想在函数内部对函数外的变量进行操作,就需要在函数内部声明其为global,以改变它的值。

考题2 单选题

运行以下代码,正确的结果是()。

def f(s):
    t=0
    max=0
    for i in s:
        if i>"0" and i<="9":
            t=t+1
        else:
            if t>max:
                max=t
            t=0
    print(max)
list="123ab45cd6d"
f(list)

A. 0 B. 1 C. 2 D. 3

答案:D

解析:本段代码中,函数f(s)的作用是求最长的连续数字字符串的长度。

考题3 判断题

调用嵌套函数outer(),两次输出变量x的值是不一样的。()

def outer():
    x="local"
    def inner():
        x="nonlocal"
        print("inner:",x)
    inner()
    print("outter:",x)

答案:正确

解析:在嵌袭函数中,其内部与外部相同名称的变量是互不影响的,所以两次输出变量的值是不一样的。

为函数的参数和返回值指定类型

知识点详解

Python是动态类型语言,新建变量时不需要声明与指定类型,自定义函数时也是如此。

但是,Python 3.5之后的版本就新增了对函数参数和返回值的类型指定和检查,新建变量时也可以指定类型。

例如下面这个函数,指定了输入参数a的类型为int,而b的类型为str,并且返回值的类型为str。

可以看到,调用此函数,最终返回了一个字符串。

def f(a:int,b:str)-> str:
    c=a*b 
    print(c)
    return f 
f(3, 'zhongguo!')

运行结果

zhongguo!zhongguo!zhongguo!

当我们调用这个函数时,如果参数a输入的是字符串,实际上运行不会报错,毕竟Python的本质还是动态类型语言。

def f(a:int,b:str)-> str:
    print(a,b)
    return 500 
f('nihao','zhongguo!')

运行结果∶

nihao zhongguo!

易错点

(1)Python 3.5之后的版本新增了对函数参数和返回值的类型指定和检查,新建变量时也可以指定类型。

(2)如果参数a输入的类型不匹配,实际上运行时不会报错。

模拟考题

考题1 编程题

设计一个算法,根据邮件的重量和用户是否选择加急计算邮费。

计算规则∶重量在1000克以内(含1000克),基本邮费8元。超过1000 克的部分,每500克加收超重费4元,不足500克部分按500克计算。如果用户选择加急,多收5元。

根据上述计算规则,编写自定义函数完成程序功能,或补全代码。

描述∶根据邮件的重量和用户是否选择加急计算邮费。

函数名∶postage(w∶int,f∶str)->int

参数表∶w代表邮件的重量(整数)。f是表示是否加急的字符串,其中'y'和'n'分别表示加急和不加急。

返回值:返回邮费(整数)。

示例∶当 w=1200,f='y'时,返回17。

def postage(w:int,f:str)->int:
    if f == 'y':
        cost = ____①____
    else:
        cost = ____②____
    if w > 1000:
        cost +=  ____③____
        if (w-1000)%500 > 0:
            cost += 4 
    return cost
w = int(input('邮件的重量:'))
f = input('是否加急:')
print(postage(w, f))

评分标准:

① 5+8或等效答案(4分);

② 8或等效答案(4分)

③ (w-1000)//500*4或等效答案(4分)。

参数传递

在 python 中,类型属于对象,对象有不同类型的区分,变量是没有类型的:

a=[1,2,3]
a="Runoob"

以上代码中,[1,2,3] 是 List 类型,"Runoob" 是 String 类型,而变量 a 是没有类型,她仅仅是一个对象的引用(一个指针),可以是指向 List 类型对象,也可以是指向 String 类型对象。

可更改与不可更改对象

在 python 中,strings, tuples和 numbers 是不可更改的对象,而 list,dict 等则是可以修改的对象。

  • 不可变类型:变量赋值 a=5 后再赋值 a=10,这里实际是新生成一个 int 值对象 10,再让 a 指向它,而 5 被丢弃,不是改变 a 的值,相当于新生成了 a。
  • 可变类型:变量赋值 la=[1,2,3,4] 后再赋值 la[2]=5 则是将 list la 的第三个元素值更改,本身la没有动,只是其内部的一部分值被修改了。

python 函数的参数传递:

  • 不可变类型:类似 C++ 的值传递,如整数、字符串、元组。如 fun(a),传递的只是 a 的值,没有影响 a 对象本身。如果在 fun(a) 内部修改 a 的值,则是新生成一个 a 的对象。
  • 可变类型:类似 C++ 的引用传递,如 列表,字典。如 fun(la),则是将 la 真正的传过去,修改后 fun 外部的 la 也会受影响

python 中一切都是对象,严格意义我们不能说值传递还是引用传递,我们应该说传不可变对象和传可变对象。

python 传不可变对象实例

通过 id() 函数来查看内存地址变化:

def change(a):
    print(id(a))   # 指向的是同一个对象
    a=10
    print(id(a))   # 一个新对象

a=1
print(id(a))
change(a)

以上实例输出结果为:

4379369136
4379369136
4379369424

可以看见在调用函数前后,形参和实参指向的是同一个对象(对象 id 相同),在函数内部修改形参后,形参指向的是不同的 id。

传可变对象实例

可变对象在函数里修改了参数,那么在调用这个函数的函数里,原始的参数也被改变了。例如:

# 可写函数说明
def changeme( mylist ):
   "修改传入的列表"
   mylist.append([1,2,3,4])
   print ("函数内取值: ", mylist)
   return

# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist)

传入函数的和在末尾添加新内容的对象用的是同一个引用。故输出结果如下:

函数内取值:  [10, 20, 30, [1, 2, 3, 4]]
函数外取值:  [10, 20, 30, [1, 2, 3, 4]]

可变对象在函数内部如果重新赋值,原始的参数不会被改变了。例如:

# 可写函数说明
def changeme( mylist ):
   #重新赋值
   mylist=[1,2,3,4]
   print ("函数内取值: ", mylist)
   return

# 调用changeme函数
mylist = [10,20,30]
changeme( mylist )
print ("函数外取值: ", mylist)

输出结果如下:

函数内取值:  [1, 2, 3, 4]
函数外取值:  [10, 20, 30]

易错点

(1)不可变对象类型参数,函数内部对参数进行修改,不会影响原实参。

(2)可变对象类型参数,函数内部对参数进行修改,会影响原实参。

(3)不可变和可变对象类型参数,函数内部如果使用”=“进行重新赋值,都不会影响原实参。

模拟考题

考题1 单选题

下列代码的输出结果是?( )

def func(a, b):
    c=a**2+b
    b=a
    return c
a=10
b=2
c=func(b,a)+a
print(c,b)

A. 102 2 B. 24 10 C. 24 2 D. 102 10

答案:C

解析:b=2,属性不可变对象,函数内部修改,不会影响外部实参

考题2 单选题

运行以下代码,输出结果正确的是?( )

a=1
b=c=[]
def fun(a,c):
    a=2
    c.append(a)
fun(a,c)
print(a,b,c)

A. 2 [2] [2]

B. 1 [] [2]

C. 1 [2] [2]

D. 2 [] [2]

答案:C

解析:a为整数为不可变类型,函数内部修改不会影响外部变量,b=c=[]为列表为可变类型,函数内部修改会影响外部变量

综合训练

实现求和函数

编写一个函数mySum,求一个列表的和(不可以可以使用原生函数sum),参考代码如下:

def mySum(a):
    s=0
    for i in a:
        s+=i
    return s
b=[1,3,5,7,9]
c=mySum(b)
print(c)

运行结果:

25

实现求最小值函数

编写一个函数myMin,求一个列表的最小值(不可以可以使用原生函数min),参考代码如下:

def myMin(a):
    minN=a[0]
    for i in a:
        if i<minN:
            minN=i
    return minN
b=[1,3,5,0,7,9]
c=myMin(b)
print(c)

运行结果:

0

函数单元测试题

模拟考题

一、单选题(共25题,每题2分,共50分)

1、有如下Python语句,执行该语句后,结果是?( )

f=lambda x:5
print(f(3))

A. 3

B. 没有输出

C. 5

D. None

2、执行如下Python代码后,结果是?( )

def inverse(s,n=0):     
  while s:
    n = n * 10 + s % 10
    s = s // 10
  return n
print(inverse(456,123))

A. 654123

B. 123456

C. 123654

D. 654321

3、如下代码运行后下面选项中描述错误的是?( )

def pph(a,b):
  c=a**2+b
  b=a
  return c
a=10
b=100
c=pph(a,b)+a
print(a,' ',b,' ',c)

A. 执行该函数后,变量a的值为10

B. 执行该函数后,变量b的值为100

C. 执行该函数后,变量c的值为200

D. 该函数名称为pph

4、有如下Python程序,执行该程序后,结果是?( )

x = 3
def  calc():
    x = 5
print(calc())

A. 3

B. 5

C. 无输出

D. None

5、关于以下程序,下列表述中错误的一项是?( )

c=1
def fun(n):
    a=1
    for b in range(1,n):
        a*=b
    return a
n=int(input('Enter n='))
print(fun(n),c)

A. c是全局变量,a是局部变量

B. n是形式参数,当n=5时,程序输出120 1

C. 程序实现求阶乘

D. range()函数是python内置函数

6、以下程序的运行结果是?( )

def f(x,y,z):     
    print(x,y,z)
f(z=3,x=2,y=1)

A. 3 2 1

B. 1 2 3

C. 2 1 3

D. 3 1 2

7、运行以下代码,正确的打印结果是?( )

def f(s):
    t=0
    max=0
    for i in s:
        if i>="0" and i<="9":
            t=t+1
        else:
            if t>max:
                max=t
            t=0
    print(max)
list="123ab45cd6d"
f(list)

A. 0

B. 1

C. 2

D. 3

8、在Python程序中,设已定义函数op,它有一个整型传值参数,一个字符串型传值参数。设x,y为整型变量,z为字符串型变量,则下列能调用该函数的正确语句是?( )

A. op

B. op(x,y,z)

C. op x,y

D. op(x+y,z)

9、运行以下程序输出的结果是?( )

x=1
def demo(): 
    global x  
    x=2   
    print(x) 
demo() 
print(x)

A. 1 1

B. 2 1

C. 1 2

D. 2 2

10、 代码:

def sum(num1,num2): 
    num1=num1+1    
    num2=num2+2     
    result=num1+num2   
    return result 
a=3 
b=4 
c=sum(a,b) 
print("a=",a,"b=",b,"c=",c)

以下说法正确的是?( )

A. 程序的运行结果为:a= 3 b= 4 c= 10

B. 程序的运行结果为:a= 4 b= 6 c= 10

C. 程序的运行结果为:a= 4 b= 6 c= 7

D. 编译错误,程序无法运行

11、有如下Python程序,包含lambda函数,运行该程序后,输出的结果是?( )

g = lambda x,y:x*y
print(g(2,3))

A. 2

B. 3

C. 6

D. 8

12、运行下列程序,输出的结果是?( )

def dtox(x,base = 2):
    s = []    
    while x>0:   
        s.append(x % base)  
        x = x // base  
    return s
print(dtox(11))

A. 报错

B. 1101

C. [1,1,0,1]

D. 1

13、运行下列程序,输出的结果是?( )

def nxs(x):
    s = 0    
    while x:    
        s = s * 10 + x % 10    
        x //= 10   
    return s

print(nxs(106))

A. 106

B. 610

C. 160

D. 601

14、对于下面的函数:

def f(x,z,y=2):
    print(x+y+z)

用f(1,2,3)和f(1,2)两个调用语句,运行结果分别是?( )

A. 都是5

B. 6和5

C. 都是6

D. 5和6

15、函数如下:

def showNumber(numbers):
      for n in numbers:
          print(n)

下面哪个选项在调用该函数时会报错?( )

A. showNumber([2,4,5])

B. showNumber('abcesf’)

C. showNumber(3.4)

D. showNumber((12,4,5))

16、 运行下列这段程序,正确的输出结果是?( )

LS = ["apple", "red", "orange"]
def funb(a):
    LS.append(a)
funb("yellow")
print(LS)

A. ["apple","red","orange"]

B. ["apple","red","orange","yellow"]

C. []

D. ["yellow"]

17、关于函数,以下选项中描述错误的是?

A. 函数能完成特定的功能,对函数的使用不需要了解函数内部实现原理,只要了解函数的输入输出方式即可

B. 使用函数的主要目的是减低编程难度和代码重用

C. Python 使用 del 保留字定义一个函数

D. 函数是一段具有特定功能的、可重用的语句组

18、函数调用时通过“键-值”形式加以指定实际参数,即使用关键字参数,可以让函数更加清晰、容易使用,关于关键字参数的限制,以下表述中哪一个是错误的?

A. 关键字参数之间不存在先后顺序

B. 不得重复提供实际参数

C. 关键字参数可以位于位置参数之前

D. 关键字参数必须位于位置参数之后

19、以下函数要计算1到100自然数的和,则划线处应补充选项为? ( )

def su(n):
    s =0
    while n > 0:
            —————————
            —————————        
       return s
print(su(100))

A. n=n-1 s=s+n

B. n=n+1 s=s+n

C. s=s+n n=n-1

D. s=s+n n=n+1

20、以下关于Python中使用函数的描述,错误的是?( )

A. 程序里一定要有main函数

B. 使用函数前要先定义函数

C. 函数在被调用时才执行

D. 函数执行结束后,程序执行流程会自动返回到函数被调用的语句之后

21、运行下列程序,输出的结果是?( )

rst = lambda a,b=5:a*b 
print(rst(5))

A. 5

B. 15

C. 25

D. 35

22、运行下列程序,输出的结果是?( )

def js(n):
    s = 0
    while n:
        s = s * 10+n % 10
        n //= 10
    return s
print(js(20230110))

A. 20230110

B. 01103202

C. 2301102

D. 1103202

23、运行下列程序后,输出的结果是?( )

def jsh(n):
    if n == 1:
        return 1
    else:
        return n + jsh(n-1)
print(jsh(10))

A. 1

B. 35

C. 45

D. 55

24、下列关于函数返回值的描述中,正确的是?( )

A. Python函数的返回值使用很灵活,可以没有返回值,可以有一个或多个返回值

B. 函数定义中最多含有一个return语句

C. 在函数定义中使用return语句时,至少给一个返回值

D. 函数只能通过print语句和return语句给出运行结果

25、 关于下列代码的描述,错误的是?( )

def fact(n):
    s=1
    for i in range(1,n+1):
        s*=i
    return s

A. s不能在函数外使用

B. range()函数是Python内置函数

C. 如果n=4,返回的值为24

D. 代码中n是可选参数

二、判断题(共10题,每题2分,共20分)

26、执行以下代码:

def fun( name, age = 30 ):
   print("Name:", name)
   print("Age:", age)
   return
fun( age=40, name="summy" )
fun( name="summy" )

程序输出的结果为:

Name: summy 
Age: 40
Name: summy
Age: 40

​ 正确 错误

27、判断下列代码的正确与错误。

def f(a,b,c):
    print(a+b,b,c-a)
f(8,b=2,6)

运行上述程序段,结果为10 2 -2。

​ 正确 错误

28、下列程序段返回的值为“Hello!Python”。

lst="Hello!Python"
def f():
    global lst
    lst="Hello!"
    return lst
f()
print(lst)

​ 正确 错误

29、下图左右两段代码运行之后,打印出的结果不相同!请判断对吗?

根据题意,该题答案为:错误.

图片2.png

​ 正确 错误

30、匿名函数L(x1,y1,x2,y2)的返回值是(x1-x2)**2 + (y1-y2)**2的计算结果。

 L = lambda x1,y1,x2,y2:(x1-x2)**2 + (y1-y2)**2

​ 正确 错误

31、在Python中调用函数的时候,必须将每个实参都关联到函数定义中的每一个形参,最简单的关联方式就是基于实参的顺序。但也可以通过关键字实参的“关键字-值”方式关联形参,这时就不必考虑函数调用过程中实参的顺序。( )

​ 正确 错误

32、函数中return语句只能放在函数定义的最后。( )

​ 正确 错误

33、Python中自定义函数的代码需要写在调用该函数之前。( )

​ 正确 错误

34、自定义函数def块中的代码不是主程序的一部分,运行会跳过该段代码。( )

​ 正确 错误

35、创建自定义函数时,不需要声明函数形参的类型,形参的类型由调用自定义函数时传递的实参类型确定。( )

​ 正确 错误

答案

一、单选题 1、C 2、C 3、C 4、D 5、B 6、C 7、D 8、D 9、D 10、A

11、C

试题解析:g = lambda x,y:x*y,lambda函数返回参数x和y的积,因此选C。

12、C 13、D

14、B

试题解析:Python函数中位置参数和关键字参数。

15、C

试题解析:3.4是浮点数,不是序列对象

16、B

试题解析:该函数作用是添加列表元素。

17、C 18、C 19、C

20、A

试题解析:Python程序不必一定要有main函数

21、C

试题解析:rst(5)传入一个实参,a被赋值为5,b使用默认值5,因此结果是5*5=25,选C

22、D

试题解析:函数js的功能是计算n的逆序数,因此选D

23、D

试题解析:递归思想求解1到n之间和,因此答案选D

24、A

试题解析:Python函数的返回值使用很灵活,可以没有返回值,可以有一个或多个返回值,是正确的。

25、D

试题解析:代码中n是可选参数是错误的

二、判断题

26、错误 27、错误 28、错误 29、正确 30、正确 31、正确

32、错误

试题解析:return语句只要在函数体内都可以,一旦执行,退出函数体

33、正确

试题解析:Python中自定义函数的代码需要写在调用该函数之前

34、正确

试题解析:def块中的代码并不是主程序的一部分,程序运行时会跳过这一部分,从def块以外的第一行代码开始运行

35、正确

试题解析:创建自定义函数时,不需要声明函数形参的类型,形参的类型由调用自定义函数时传递的实参类型确定

Copyright © all right reserved,powered by Gitbook该文件修订时间: 2023-09-23 20:30:58