有返回值的函数



文章目录

  • 有返回值的函数
  • 1、返回值
  • 2、增量式开发
  • 3、组合
  • 4、布尔函数
  • 5、再谈递归
  • 6、信仰之跃
  • 7、再举一例
  • 8、检查类型
  • 9、调试



  • 空函数(void) :产生某种效果,像打印一个值或是移动乌龟,但是并不产生一个值;
  • 有返回值的函数 :调用这样的函数会生成一个值, 通常将其赋值给某个变量或是作为表达式的一部分;

1、返回值

  • 返回值:调用一个函数会生成一个值,这个值称为函数的返回值
  • 调用一个有返回值的函数会生成一个值;
  • 通常将函数返回值赋值给某个变量或是作为表达式的一部分;
  • 空函数,泛泛地来看,它们没有返回值,更准确地说,它们的返回值是 None ;
  • 有返回值的函数中,以包含一个表达式的 return 语句结束:“马上从该函数返回,并使用接下来的表达式作为返回值”;
  • return 语句中表达式可以是任意复杂的;
  • 条件语句的每一个分支内各有一个返回语句会很有用,一旦一条返回语句执行,函数则终止,不再执行后续的语句;
  • 出现在某条return语句之后的代码,或者在执行流程永远不会到达之处的代码,被称为死代码(dead code);
  • 在一个有返回值的函数中, 最好保证程序执行的每一个流程最终都会碰到一个 return 语句;
  • 函数按照流程执行完毕,未碰到一个 return 语句,返回值将是 None;
def absolute_value(x):
    if x < 0:
        return -x
    if x > 0:
        return x
>>> absolute_value(0)
None
def compare(x, y):
	if x > y:
		return 1
	elif x < y:
		return -1
	elif x == y:
		return 0
		
print(compare(10,10))
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new23.py
0

2、增量式开发

  • 增量式开发( incremental development ) :通过每次只增加和测试少量代码,来避免长时间的调试,这种开发方式即为增量式开发( incremental development )
  • 从一个能运行的程序开始,并且每次只增加少量改动,无论你何时遇到错误,都能够清楚定位错误的源头;
  • 用临时变量存储中间值,这样你就能显示并检查它们;
  • 一旦程序正确运行,你要删除一些脚手架代码,或者将多条语句组成复合表达式,但是前提是不会影响程序的可读性;
def hypotenuse1(a,b):
	return 0
	
def hypotenuse2(a, b):
	squared = a**2 + b**2
	print("squared = ",squared)
	return 0
	
def hypotenuse3(a, b):
	squared = a**2 + b**2
	c = math.sqrt(squared)
	print("c = ",c)
	return 0 
	
def hypotenuse(a, b):
	squared = a**2 + b**2
	c = math.sqrt(squared)
	return c
	
print(hypotenuse1(3,4))

print(hypotenuse2(3,4))

import math
print(hypotenuse3(3,4))

print(hypotenuse(3,4))
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new24.py
0
squared =  25
0
c =  5.0
0
5.0
  • 脚手架代码(scaffolding) :上述练习中,print("squared = ",squared)这样的代码对程序的构建很有用,但不是最终产品的一部分,这样的代码即为脚手架代码(scaffolding)

3、组合

  • 可以从一个函数内部调用另一个函数;
def area(radius):
    return math.pi * radius**2
def distance(x1, y1, x2, y2):
    dx = x2 - x1
    dy = y2 - y1
    dsquared = dx**2 + dy**2
    result = math.sqrt(dsquared)
    return result
def circle_area(xc, yc, xp, yp):
    return area(distance(xc, yc, xp, yp))

4、布尔函数

  • 函数可以返回布尔值(booleans);
  • 布尔函数返回值:True 或者 False(如果无返回值,则为 None );
def is_between(x, y, z) :
	if x <= y and y <= z:
		return True
	else:
		return False
		
print(is_between(5, 6, 4))
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new25.py
False

5、再谈递归

  • 一个递归定义的函数的例子(阶乘函数 factorial):
def factorial(n):
    if n == 0:
        return 1
    else:
    	recurse = factorial(n-1)
        result = n * recurse
        return result
  • 递归定义类似循环定义,因为定义中包含一个对已经被定义的事物的引用;
  • 上面递归定义的函数(阶乘函数)引入实参3时的堆栈图:

iOS 空函数内部是否有其他东西 空函数有没有返回值_iOS 空函数内部是否有其他东西

6、信仰之跃

  • “信仰之跃”:阅读代码,当遇到一个函数调用时,不再去跟踪程序执行流程,而是假设这个函数正确运行并返回了正确的结果;
  • 当遇到递归调用时, 不用顺着执行流程,应该假设每次递归调用能够正确工作(返回正确的结果);
  • 当然,在没写完函数的时就假设函数正确工作有一点儿奇怪, 但这也是为什么这被称作信仰之跃了;

7、再举一例

  • 另一个递归定义的函数(斐波那契数列 fibonacci ):
def fibonacci (n):
    if n == 0:
        return 0
    elif  n == 1:
        return 1
    else:
        return fibonacci(n-1) + fibonacci(n-2)
  • 如果试图跟踪执行流程,即使是相当小的 n ,也足够头疼的,但遵循信仰之跃这种方法,如果假设这两个递归调用都能正确运行,很明显将他们两个相加就是正确结果;

8、检查类型

  • 重构后的阶乘函数,演示了一个有时被称作监护人(guardian) 的模式:
def factorial (n):
    if not isinstance(n, int):
        print('Factorial is only defined for integers.')
        return None
    elif n < 0:
        print('Factorial is not defined for negative integers.')
        return None
    elif n == 0:
        return 1
    else:
        return n * factorial(n-1)
  • 前两个条件扮演监护人的角色,避免接下来的代码使用引发错误的值;
  • 监护人使得验证代码的正确性成为可能;

9、调试

  • 将一个大程序分解为较小的函数为调试生成了自然的检查点, 如果一个函数不如预期的运行,有三个可能性需要考虑:
  • 该函数获得的实参有些问题,违反先决条件;
  • 该函数有些问题,违反后置条件;
  • 返回值或者它的使用方法有问题;
  • 为了排除第一种可能,你以在函数的开始增加一条 print 语句来打印形参的值(也可以是它们的类型), 或者你可以写代码来显示地检查先决条件;
  • 如果形参看起来没问题,就在每个 return 语句之前增加一条 print 语句,来打印返回值;
  • 如果可能,手工检查结果;
  • 考虑用一些容易检查的值来调用该函数;
  • 如果该函数看起来正常工作,则检查函数调用,确保返回值被正确的使用(或者的确被使用了!);
  • 在一个函数的开始和结尾处增加打印语句,可以使执行流程更明显;
def factorial(n):
    space = ' ' * (4 * n)
    print(space, 'factorial', n)
    if n == 0:
        print(space, 'returning 1')
        return 1
    else:
        recurse = factorial(n-1)
        result = n * recurse
        print(space, 'returning', result)
        return result
        
factorial(4)
PS C:\Users\Administrator> python D:\WorkSpace\thinkpython2e\new26.py
                 factorial 4
             factorial 3
         factorial 2
     factorial 1
 factorial 0
 returning 1
     returning 1
         returning 2
             returning 6
                 returning 24