Python入门教程-04 再论函数

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知识。



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值