函数根据有没有参数,有没有返回值,可以相互组合,一共有4种
-
无参数,无返回值
-
无参数,有返回值
-
有参数,无返回值
-
有参数,有返回值
-
函数嵌套
-
封装 - 数据隐藏
可以使用内层函数来保护它们不受函数外部变化的影响,也就是说把它们从全局作用域隐藏起来。
来看一个简单的例子 - 求一个数字 n 的倍数:
>>> def outer(n):
... def inner_multiple(n): # 从外部代码隐藏
... return n * 2
... num = inner_multiple(n)
... print(num)
...
>>>1234567尝试调用 inner_multiple(n) 会引发错误:
>>> outer(5)
10
>>>
>>> inner_multiple(5) # 外部无法访问
...
NameError: name 'inner_multiple' is not defined123456这是因为它被定义在 outer() 的内部,被隐藏了起来,所以外部无法访问。
在 Python 递归函数 一节中,分享过一个关于阶乘的递归实现,但是存在一个问题 - 没有做容错处理。
下面来利用嵌套函数,对递归做一个更好的实现:
>>> def factorial(n):
...
... # 错误处理
... if not isinstance(n, int): # 仅限整形
... raise TypeError("Sorry. 'n' must be an integer.")
... if n < 0: # 仅限 0 和 正数
... raise ValueError("Sorry. 'n' must be zero or positive.")
...
... def inner_factorial(n):
... if n <= 1:
... return 1
... return n * inner_factorial(n - 1)
... return inner_factorial(n)
...
>>> 123456789101112131415这样以来,程序就会变得更加健壮,当数据类型或值不合理时,便会引发错误:
>>> factorial('Py') # 类型错误
...
TypeError: Sorry. 'n' must be an integer.
>>>
>>> factorial(-10) # 值错误
...
ValueError: Sorry. 'n' must be zero or positive.
>>>
>>> factorial(5) # OK
12012345678910使用这种模式的主要优势在于:利用外部函数执行所有的参数检查,便可以在内部函数中跳过错误检查,并安全放心地进行使用
>>> def print_file(f):
... for line in f:
... print(line)
...
>>> f = open('data.txt', 'r')
>>> print_file(f)
Hi, allI am a Pythonista
>>> 1234567891011
支持文件名:
>>> def print_file_content(file_name):
... if isinstance(file_name, str):
... with open(file_name, 'r') as f:
... for line in f:
... print(line)
...
>>> print_file_content('data.txt')
Hi, allI am a Pythonista
>>> 123456789101112
很显然,有很多代码可以复用,通过嵌套函数来实现:
>>> def print_file(file):
... def inner_print(file_process):
... for line in file_process:
... print(line, end = '')
...
... if isinstance(file, str):
... with open(file, 'r') as f:
... inner_print(f)
... else:
... inner_print(file)
...
>>>
---------------------
!