您的位置:首页 > 编程语言 > Python开发

Python入门教程-04 再论函数

2014-04-13 17:37 435 查看

1. Overview

在上一节中,我们简单用到了函数、简单介绍了函数的语法。本节进一步介绍和函数相关的一些方面。

2. 函数:返回值

在C、C++、Java中,只有函数function这一种说法;如果大家用过VB等编程语言,知道会有函数function和过程process之分,前者有返回值,后者没有返回值。那么在Python中,和C/C++/Java一样,只有function一说。

继续前面Fibonacci的例子,但这里做一定的修改:

#!/usr/bin/env python

def Fibonacci(n):
if n == 0:
return 0
elif n == 1:
return 1
else:
return Fibonacci(n - 1) + Fibonacci(n - 2)

def Dump_Fibonacci(n, val):
print "Fibonacci(%d) = %d\n" % (n, val)

n = 10
val = Fibonacci(n)
Dump_Fibonacci(n, val)


这里,我们定义了2个函数:Fibonacci和Dump_Fibonacci。前者返回一个整数,后者不返回任何数据。

3. return语句

return语句的使用方法和其他编程语言是一样的,其实无需多言。这里只简单指出:在Python中,return语句之后,仍然可以有其他的语句。

什么意思呢?用过Java语言的知道,不能存在不可达(Unreachable)代码。比如在return语句之后,再定义根本无法执行到的一些代码,那么就会有编译错误。而在Python中,使用和C/C++一样的语法规则,即在return语句之后还可以有其他的代码。这样的语法的好处就是,便于调试。——因为有时候一个函数的功能很复杂、代码很长,那么就可以在函数中间添加return来调试部分代码,从而加快调试的效率。——BTW:如果经常出现这种情况,就要考虑该函数是否需要重构!

示例:

flying-bird@flyingbird:~/examples/python$ cat unreachable.py
#!/usr/bin/env python

def Unreachable():
print "first line."

return

print "Unreachable code."

Unreachable()

flying-bird@flyingbird:~/examples/python$ ./unreachable.py
first line.
flying-bird@flyingbird:~/examples/python$


4. 再论返回值

在前面介绍了函数的常用规则之后,我们简单提及一个事实,即:虽然函数没有return语句,但该函数仍然有返回值,只是该返回值极其特殊,为None。因为是None,自然没有多大用处。

示例:

flying-bird@flyingbird:~/examples/python$ cat return_none.py
#!/usr/bin/env python

def Print(msg):
print msg

def Add(x, y):
z = x + y

ret = Print("Hello, python!")
print "ret: ", ret

ret = Add(3, 2)
print "ret: ", ret

flying-bird@flyingbird:~/examples/python$ ./return_none.py
Hello, python!
ret:  None
ret:  None
flying-bird@flyingbird:~/examples/python$


注意,这里给出Add()是有意的。因为在某些语言中,如果没有return语句,那么它会将函数最后执行的一条语句的结果作为返回值。而上面的示例说明了,在Add()函数中,虽然最后一条语句计算除了z,但并没有将z作为返回值。

5. 参数的数据类型

前面已多次提及Python中的变量不需要定义其数据类型(无语法支持),那么如何才能知道函数参数是什么类型呢?答案很简单:基于契约,即caller和callee之间的调用约定。

当然,可以在函数中对入参的类型进行校验,如使用
Python入门教程-02 变量 一文提到的type()方法。但实际项目中,很少采用这种做法,因为这已经涉嫌“过设计”了。

进一步地,如果caller提供的参数非法,那么脚本执行时,会直接异常终止。示例:

flying-bird@flyingbird:~/examples/python$ cat return_none.py
#!/usr/bin/env python

def Print(msg):
print msg

def Add(x, y):
z = x + y

ret = Print("Hello, python!")
print "ret: ", ret

ret = Add(3, "2")
print "ret: ", ret

flying-bird@flyingbird:~/examples/python$ ./return_none.py
Hello, python!
ret:  None
Traceback (most recent call last):
File "./return_none.py", line 12, in <module>
ret = Add(3, "2")
File "./return_none.py", line 7, in Add
z = x + y
TypeError: unsupported operand type(s) for +: 'int' and 'str'
flying-bird@flyingbird:~/examples/python$


6. Pass-by-Val or Pass-by-Ref

继续和C/C++进行类比。在C/C++中,存在传值和传引用的概念。那么在Python是否也是如此呢?或者说,传给函数的变量,可以修改吗?

为此,先通过例子进行说明:

flying-bird@flyingbird:~/examples/python$ cat incr.py
#!/usr/bin/env python

def Inc(x):
x = x + 1
return x

x = 100
y = Inc(x)
print "x: ", x
print "y: ", y

flying-bird@flyingbird:~/examples/python$ ./incr.py
x:  100
y:  101
flying-bird@flyingbird:~/examples/python$


通过这个小例子,我们似乎可以给出如下结论:

Python中函数参数不存在传值或传引用的说法,或者说,全部都是传值的形式;
在函数内部可以修改入参的值,但该修改仅仅在该函数内部其作用,并不会影响调用程序中该变量的值;

但事实是否果真如此呢?如果大家有Java语言编程经验的话,或许还知道值对象和引用对象的概念。在深入介绍该专题之前,我们再给出一个例子:

flying-bird@flyingbird:~/examples/python$ cat incr.py
#!/usr/bin/env python

def Inc(x):
x = x + 1
return x

def Append(x):
x.append(100)
return x

x = 100
y = Inc(x)
print "x: ", x
print "y: ", y

x = [1, 2, 3]
y = Append(x)
print "x: ", x
print "y: ", y

flying-bird@flyingbird:~/examples/python$ ./incr.py
x:  100
y:  101
x:  [1, 2, 3, 100]
y:  [1, 2, 3, 100]
flying-bird@flyingbird:~/examples/python$


这个例子用到了Python中非常重要的一种数据类型,即list。至此,说明了Python的入参存在和java类似的处理机制,而和C++又存在差异了。——如果是值引用,后者会使用拷贝构造定义出一个临时变量。

我们先了解Python函数入参的这个复杂性,在后续介绍list, set, dictionary, class等专题的时候,我们会再次进行这方面的讲解。

7. 缺省参数

和C++一样,Python也支持缺省参数。即在定义函数的时候,可以为这个参数定义一个缺省值。如此在调用该函数的时候,如果没有指定该参数,则使用该参数的缺省值;如果指定了具体的值,则使用传入的这个数据。示例:

flying-bird@flyingbird:~/examples/python$ cat default_arg_value.py
#!/usr/bin/env python

def Inc(x, step=1):
x = x + step
return x

def debug(step):
x = 100
if step == 1:
y = Inc(x)
else:
y = Inc(x, step)

print "x: ", x
print "y: ", y

debug(1)
debug(10)

flying-bird@flyingbird:~/examples/python$ ./default_arg_value.py
x:  100
y:  101
x:  100
y:  110
flying-bird@flyingbird:~/examples/python$


8. 其它

关于函数还有很多专题可以介绍,比如命名参数、变长参数等等。但在目前,我们先掌握前面介绍的基础知识。待所有基本语法全部浏览一遍之后,我们再回过头来深入每一个专题。——可以将我们的学习过程看作是敏捷迭代的方式,即通过快速地掌握最基本的语法,能够编写基本的、小型的、常见的Python程序。然后逐步深入每一个专题,逐步完善我们的Python知识。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: