3 函数

1. 基础知识

1.1 函数的概念

目前为止,我们学习过了赋值语句,输入输出,分支结构和循环结构,已经可以完成简单代码的编写。但是,试想一下,如果需要完成成千上万行的代码编写,一些特定功能的语句在代码中反复出现时,我们是否有更好的方式来缩减代码量。因此,为了在大型程序里减少编码工作量,我们引入了模块化的编程思想。简单来讲,这种思想包含两个部分:一是分解,二是抽象。分解讲一个问题分解成多个模块,每个模块代表一个功能,通过多个模块的组合来完成解决问题。抽象是指我们在编写模块的时候可以忽略细节,只关注这个模块的输入是什么,输出是什么即可,类似于一个黑盒子。给予这种思想,我们引入函数的概念。

在程序设计中,函数(function)是指一个有命名的、执行某个计算的语句序列。在定义一个函数的时候,你需要指定函数名和语句序列。之后,你可以通过定义的函数名字调用(call)该函数。这里需要注意,函数就类似于上面提到的黑盒子,我们在使用一个函数时,应该重点关注该函数的输入(类型和值)是什么,输出(类型和值)是什么。

Python内置函数

在Python中,包含许多内置的实现特定功能的函数,例如已经学过的print(),input(),int()等函数。使用这些函数被称为函数的调用(细节见函数调用部分)

自定义函数编写

当我们想实现一些特殊的功能时,我们需要自己编写函数来实现这些特定功能。编写函数的语法形式如下:

def <函数名>(<参数列表>):

       <函数体>

       return <返回值列表>

其中,def是Python的关键字,当解释器碰到def时,就意味着告诉解释器,这个位置要创建一个函数。函数名是任何有效的Python标识符;参数列表是调用该函数式传递给它的值,可以有零个,一个或者多个,被称为形式参数;函数体是函数每次调用时执行的代码;return语句有两个功能:第一,结束函数;第二,返回列表中的值。

None关键字(暂时略)

函数的调用

函数的调用和执行的一般形式如下:

<函数名>(<参数列表>)

此处的参数列表是要传入函数内部的参数,称为实际参数。

函数调用的过程包括以下四个步骤:
(1)调用程序在调用处停止

(2)在调用时将实参赋值给函数的形参

(3)执行函数体语句

(4)函数调用结束给出返回值,程序回到调用前的暂停出继续执行。

参数传递

函数定义中可能包括多个形参,因此函数调用中也可能包含多个实参。向函数传递实参的方式很多,可使用位置实参,这要求实参的顺序与形参的顺序相同;也可使用关键字实参,其中每个实参都由变量名和值组成,我们先来学习位置实参。

当调用函数时,Python必须将函数调用中的每个实参都关联到函数定义中的一个形参,最简单的关联方式是基于实参的顺序。这个方式被称为位置实参。

除了位置实参之外,Python中还有通过关键字传递实参的方式,称为关键字实参。这种方式是直接将实参中的名称与值关联起来。(这种方法暂时忽略)

函数的局部作用域与全局作用域

在被调函数内赋值的变量,处于该函数的“局部作用域”。在所有函数之外赋值的变量,属于“全局作用域”。处于局部作用域的变量被称为“局部变量”。处于全局作用域的变量,被称为“全局变量”。我们可以将“作用域”看成是变量的容器。当作用域被销毁时,所有保存在该作用域内的变量的值就被丢弃了。例如:

def f(x):
    x=x+1
    a=x+2
    return a

x=3
c=f(3)

 

2. 实验步骤

2.1 函数的调用与返回

在之前的学习中,已经使用到了函数的调用。回想一下,我们是如何使用type()和 print()函数的?例如,我们在解释器中输入type(42),会出现什么结果:           。这个有type()函数输出的结果就叫做该函数的返回值(return value)。现在请验证int(), float()和str()函数的作用,明确其输入值和返回值。当我们阅读别人程序的时候,出现没有见过的函数,应该怎么办?

2.2自定义函数

当我们想实现一些特殊的功能而Python的自带函数中没有我们所需要的功能时,我们就需要自己编写函数来实现我们需要的特定功能。下面,我们来实现一个打印问候语的简单函数:

函数定义

新建一个函数,在编辑器中输入以下代码:

1

2

3

4

5

def greet_user():

    '''打印显示问候语'''

    print("hello")

   

greet_user()

上面的例子就是一个最简单的函数结构。第一行的代码使用了关键字def来告诉Python你要定义一个函数。这是函数定义,向Python指出函数名,还可能在括号内指出函数为完成其任务需要的信息。在这个例子当中,函数名是greet_user(),它不需要任何信息就能完成其工作,因此括号内是空的。注意即便如此,括号也必不可少。最后,定义以冒号结尾。在def greet_user():后面的所有缩进体构成了函数体。我们注意到第二行中的文本信息是由两个'''包括的,请思考一下'''和#的区别?

第三行是函数体内的唯一代码,实现的功能为打印Hello。最后一行是函数调用,目的是告诉Python要执行函数greet_user()中的代码。

像函数传递信息

稍作修改,可以让函数greet_user()不仅显示Hello,还可以显示用户的名字。为此,可在函数定义时在括号内添加username,通过添加username,可以让函数接受你给username指定的任何值。如以下所示:

1

2

3

def greet_user(name):

    '''打印显示问候语'''

    print("hello"+name+"!")

请在name变量里指定你的名字,并调用greet_user()函数打印输出。

实际参数和形式参数

前面定义函数greet_user()时,要求给变量username指定一个值。调用这个函数并提供这种信息(人名)时,它将打印相应的问候语。在函数greet_user()的定义中,变量username是一个形式参数——函数完成其工作所需要的一项信息。在代码greet_user('James')中,字符串'James'是一个实际参数——调用函数时所传递给函数的信息。因此,在greet_user('James')中,将实参'James'传递给了函数greet_user(),这个值被存储在形参username中。

传递实参

实参传递有两种方式,一种是按位置传递,一种是按关键字传递。请输入以下代码,体会两种传递方式的区别。

1

2

3

4

5

6

7

def greet_user(name,age):

    '''打印显示问候语'''

    print("hello"+name+"!")

    print("Your age is "+age+".")

   

greet_user('小明','19')

greet_user(age='19',name='小明')

2.3函数的返回值

函数并非总是直接显示输出,相反,它可以处理一些数据,并返回一个或一组值。在函数中,可以使用return语句将值返回到调用函数的代码行。返回值的作用是能够将程序中大部分繁重的工作移动到函数中去完成,从而简化主程序。请输入以下代码:

1

2

3

4

5

6

7

def get_information_name(Xing,Ming):

    '''返回简洁的姓名'''

    Xing_Ming_Temp=Xing+' '+Ming

    return Xing_Ming_Temp

 

Xing_Ming=get_information_name('Zhang','Xiaoming')

print(Xing_Ming)

2.4局部作用域与全局作用域

现在,我们将以上代码的第三行和第四行的变量Xing_Ming_Temp改为Xing_Ming,运行该程序,我们发现输出结果没有变化,第三行和第六行的变量名均为Xing_Ming,但是Python并没有将两个变量混淆,原因就在于变量的作用于。下面,我们来探索全局和局部作用域的几点性质:

Step 1:将代码中的第六行删除,第七行改为print(Xing_Ming_Temp),运行程序,可得出什么结论?                                                                              

Step 2:修改代码如下:

1

2

3

4

5

6

7

8

9

10

11

def get_information_name(Xing,Ming):

    '''返回简洁的姓名'''

    test()

    Xing_Ming_Temp=Xing+' '+Ming

    return Xing_Ming_Temp

 

def test():

    Ming='Daming'

 

Xing_Ming=get_information_name('Zhang','Xiaoming')

print(Xing_Ming)

运行程序,可得出什么结论?                      

Step 3:修改代码如下:

1

2

3

4

5

6

7

8

9

10

def get_information_name():

    '''返回简洁的姓名'''

    Xing_Ming_Temp=Xing+' '+Ming

    return Xing_Ming_Temp

 

Xing='Zhang'

Ming='Daming'

 

Xing_Ming=get_information_name()

print(Xing_Ming)

运行程序,可得出什么结论?

Step 4:修改代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

def test1():

    Xing_Ming='Han Wei 1'

    print(Xing_Ming)

   

def test2():

    Xing_Ming='Han Wei 2'

    print(Xing_Ming)

   

Xing_Ming='Han Wei'

print(Xing_Ming)

test1()

test2()

运行以上代码,可得出什么结论?

其中,第二行Xing_Ming变量为            作用域,第六行Xing_Ming变量为           作用域,第九行Xing_Ming变量为           作用域。

通过以上例子,我们总结4条法则,来区分一个变量是处于全局作用域还是局部作用域:

如果变量在全局作用域中使用,它就总是全局变量;

如果一个函数中,有针对该变量的global语句,它就是全局变量;

否则,如果该变量用于函数中的赋值语句,它就是局部变量;

但是,如果该变量没有用在函数的赋值语句中,它就是全局变量。

3练习题

3.1 定义两个函数,分别用于将小写字母转换为大写和将大写字母转换为小写。

3.2 编写一个函数,计算n!,并依次输出1~20的阶乘。

注:分别用两种方法进行定义和调用。

3.3 编写程序,计算如下序列的值:1-2+3-4…996,其中,所有数字为整数,从1开始递增,奇数为正,偶数为负。

3.4 恺撒密码是古罗马恺撒大帝用来对军事情报进行加解密的算法,它采用了替换方法对信息中的每一个英文字符循环替换为字母表序列中该字符后面的第三个字符,即,字母表的对应关系如下:‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫

原文:A B C D E F G H I J K L M N O P Q R S T U V W X Y Z‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫

密文:D E F G H I J K L M N O P Q R S T U V W X Y Z A B C‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫

对于原文字符P,其密文字符C满足如下条件:C=(P+3) mod 26‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫。上述是凯撒密码的加密方法,解密方法反之,即:P=(C-3) mod 26‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫。假设用户可能使用的输入包含大小写字母a~zA~Z、空格和特殊符号,请编写一个程序,对输入字符串进行恺撒密码加密,直接输出结果,其中空格不用进行加密处理。使用input()获得输入。‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫‪‪‪‪‪‪‪‪‪‪‪‪‫

3.5 编写函数,完成进制转换。要求:

函数输入:原始进制,原始进制表示的数,转换进制

函数输出:转换后的数。

例如:在输入2,101,10,输出为5。即将二进制数101转换成10进制的数

3.6 编写一个函数,输入某月某日,判断这一天是这一年的第几天?

 

猜你喜欢

转载自blog.csdn.net/Liverpool_05/article/details/83241949