七、Python的函数编程(之一)

最后更新于:2022-04-01 21:47:30

                        ## 七、Python的函数编程(之一)

----From a high schoolstudent's view to learn Python

关键字:

python 高中生学编程 MIT公开课视频Python函数编程 递归 递归函数 递归调用

一、为什么会引入函数


在学习的初期阶段,我们写的程序都比较简单,功能比较单一,代码的行数也不会太多;那我们想一想,如果需要处理的应用越来越复杂,我们是不是顺着我们的思路,一直将我们的代码在一个地方不停地写下去呢?如果这样下去,会是什么结果呢?

你可以想一想,如果一部长篇小说,没有章节划分,甚至连段落都没有,拿到它进行阅读,会是怎样的阅读感受呢?

其实,我们编写代码,一方面实现代码的功能,另一方面还需要具有较好的可读性,便于维护、修改、和别人使用;所以,随着功能变得复杂,我们会将应用进行分割,简单化、模块化,就象买回来的组装玩具一样,函数(Function)就是这些玩具的各个部件。

我们在学习之初,都用到了print,print其实就是一个函数,只不过它是系统提供的一个函数,他可以被任何人在任何时候使用,来实现它的功能。

下面剪辑的视频还是来自MIT的公开课视频,比较详细的介绍了在编程中为何需要引入函数;

【这里插入视频】

为什么需要引入函数的视频

函数的实际应用讲解

二、函数的定义


  1. 函数的定义

我们从一个例子开始,这是一个可以计算任意大小的斐波那契数列的函数:

1

2

3

4

5

6


def fib(n):  # write Fibonacci series up ton 

  """Print a Fibonacci series up ton.""" 

   a, b = 0, 1 

   while a <n: 

       printa, 

       a, b = b,a+b


在详细的介绍函数的定义之前,我们先看看这段代码:

line 1:定义函数

line2:还记得吗,这是一行注释,三引号(单引号效果一项)

line3:比较奇特,其实就是赋值语句,对于多个变量需要赋值时,可以按照这样的方式来写,看着比较简洁,按照等号前面的变量顺序,逐个将后面的值赋给变量,这里给变量赋的都是整数,其实任意类型都可以,如:

aa, bb, cc, dd = 1, 2.3, 1.3e2,“string”

line4:while循环语句,注意写这样的语句,不要忘记”:”

line5:这一句我们应该很熟了,但是注意a后面的”,”;这表示在print变量a之后,不换行,因为是循环,所以在下次执行这个print语句时,print的内容会跟在上一次print的后面,不会换行;但是,如果没有”,”那每次执行完print都会自动换行

line 6:在line3我们介绍了这是一种赋值的写法,这一句又深入了,赋值的内容是多个表达式

特别再次强调:注意缩进,本例有两层缩进

函数的定义:

要素一:关键字def

要素二:函数名,和变量名的规则差不多,但是一般好的编程风格是将函数名和它实现的功能变现出来

要素三:函数名后面有一对()

要素四:()中可以含有一个和多个参数,当然也可以没有参数

要素五:”:”

要素六:函数体必须缩进

  1. 函数的调用

函数在定义了之后,我们只有进行调用,函数才能够执行,其实在使用print语句的时候,我们就是在“调用print函数“。

那如何调用我们在上面给出的示例呢?

...>>># Now call the function wejust defined: 

...fib(2000) 

0 1 1 2 3 5 8 13 21 34 55 89144 233 377 610 987 1597 

fib(2000)就是调用,在下面的一行,就是该函数的执行结果,显示了2000以下的斐波那契数列;因为我们在printa后面加了”,”,所以数列显示在一行,否则,这些数将一行一个竖着显示出来。

  1. 关于函数的参数

函数的参数对我们初学者,是比较绕的(个人感觉),其实跟我们数学中的函数有异曲同工之处,数学中的函数如:

y=f(x)

y=f(x1,y1)

y=f(x1, x2, …, xn)

所以,我们可以这么理解:

函数的参数就相当于我们数学中函数的自变量。

函数可以没有参数,也可以有一个或多个参数。

还有一种特殊情况:

回想一下print的使用,我们可以:

print a

也可以:

print a, b, c, d, e

也就是说,参数的数量是可变的。

以上只是简单的概念性介绍,python在函数参数方面还有很多特点:

1) 缺省参数(default argumentvalues)

1

2

3

4

5

6


deffib(n=2000):   # writeFibonacci series up to n 

  """Print a Fibonacci series up ton.""" 

   a, b = 0, 1 

   while a <n: 

       printa, 

       a, b = b,a+b


这样定义的函数,我们在调用时,可以直接使用

fib() 

0 1 1 2 3 5 8 13 21 34 55 89144 233 377 610 987 1597 

但是,如果不是缺省参数定义,这样调用系统会报错:


fib()

Traceback (most recent calllast):

 File"<stdin>", line 1, in<module>

TypeError: fib() takes exactly1 argument (0 given)

2) 关键字参数(keywordarguments)

关键字参数是针对函数调用而进行设计的语法规则;

对于函数:

function_ex(arg1, arg2=”arg2”,arg3)

pass#关键字,用来占位

我们可以采用以下的几种方法来调用(我们假设参数的类型为string):

function_ex(“arg1”)

function_ex(arg1=”arg111”,“arg333”)

function_ex(”arg111”,arg3=“arg333”)

function_ex(arg3=”arg333”,arg1=”arg111”,arg2=”arg222”)

  

采用关键字参数可以不按照参数列表的实际顺序,但是尽量按照顺序来写,否则很容易引起错误

4. 函数的返回值

还是拿我们数学的函数来进行说明:

对于函数:

y=f(x)

y=f(x1,y1)

y=f(x1, x2, …, xn)

如果我们给定自变量值,肯定有一个y值对应,我们可以类似的认为,y就是函数的返回值。

将上面的fib函数稍作修改:

1

2

3

4

5

6

7

8

def fib2(n): # returnFibonacci series up to n 

  """Return a list containing the Fibonacciseries up to n.""" 

   result = [] 

   a, b = 0, 1 

   while a <n: 

      result.append(a)   # seebelow 

       a, b = b,a+b 

   return result

修改之处有:

line1:我们重新取了个名,现在函数名为fib2

line3:新增加了一个变量result,还记得吗,[]表示list类型,我们给result初始化成一个空得list,这一句实现了两个目的:一是隐含的说明了result是一个list类型的变量,二是对变量进行了初始化

line6:这句会比较难懂,list类型在前面的博客中已经有介绍,它包含有有很多的“方法(method)“,来实现各种不同的功能,如:append用来添加一个元素到list,pop可以将list的最后一个元素弹出等…,注意这种调用的写法。result.append(a)等同于result= result + [a]

line7:返回result

对于返回值,还需要强调:

要素一:

函数可以没有return语句,但在没有return时,返回值是None,这也是一个保留关键字;


fib(0)&nbsp;

printfib(0)&nbsp;

None

要素二:

return语句可以没有值,这种情况,也返回None

要素三:

正常情况,return value

下面是一段视频讲解

插入视频

三、变量的作用域


我们在程序中会定义很多的变量,在引入了函数之后,变量的作用域(或者说变量的可使用范围)就需要仔细的考虑了。

在函数的外面定义的变量,在函数里可以使用吗?

在函数里定义的变量,在函数体之外还能够使用吗?

这些都是我们在这一节讨论的问题。

1、局部变量

简单的说,在函数体之内定义的变量,它的作用域就被限定在函数体内,如果在函数体外使用,就会报错

def func_test01():

...    a1=10

...    print a1

... 

func_test01()

10

print a1

Traceback (most recent calllast):

File"", line 1, in

NameError: name 'a1' is notdefined

2、全局变量

如上述,反之就是全局变量,看如下示例:


a1=1

def test_func():

... &nbsp;&nbsp; print a1

... &nbsp;&nbsp; print a2

...&nbsp;

a2=2

test_func()

1

2

就算a2定义在函数的后面,在函数中也是可以使用的

3、强制为全局变量

如果在函数体内声明一个与全局变量一样名字的变量时,这时候,全局变量将被覆盖,如同声明了一个名字一样的局部变量。

1

2

3

4

5

6

7

8

9

def foo():

   print "\ncalling foo()..."

   bar = 200

   print "in foo(), bar is", bar


bar = 100

print "in __main__, bar is",bar

foo()

print "\nin __main__, bar is(still)", bar

得出的输出结果如下:


in __main__, bar is100

calling foo()...

in foo(), bar is 200

in __main__, bar is (still)100

如何解决这种问题?这就需要使用global来强制将变量设为全局变量,改动如下:

1

2

3

4

5

6

7

8

9

10

def foo():

   global bar

   print "\ncalling foo()..."

   bar = 200

   print "in foo(), bar is", bar


bar = 100

print "in __main__, bar is",bar

foo()

print "\nin __main__, bar is(still)", bar

得出的输出结果如下:


in __main__, bar is100

calling foo()...

in foo(), bar is 200

in __main__, bar is (still)200

  

这样的话,在调用函数之后,bar的值变被更改了。

我的更多文章:

  • Python程序调试的一些体会(2013-10-06 22:57:35)
  • 十四、Python编程计算24点(之二)(2013-10-03 22:18:28)
  • 十三、Python编程计算24点(之一) (2013-10-02 22:15:46)
  • 十二、Python简单数据结构应用(之二)(2013-10-02 22:10:41)
  • 十一、Python简单数据结构应用(之一)(2013-09-23 23:31:49)
  • 十、Python编程解决组合问题(之二) (2013-09-21 23:37:27)
  • 九、Python编程解决组合问题(之一)(2013-09-21 23:32:54)
  • 八、Python的函数编程(之二) (2013-09-20 23:09:39)
  • 六、Python的程序流程(2013-09-19 16:53:58)
  • 高中生如何学编程(2013-09-02 19:26:01)
';