内层函数——它们的优点是什么?
让我们看一下写内层函数的三个常见原因。
记住:在Python中,函数是“一等公民”,这意味着它们和其他对象平起平坐(例如:整型,字符串,列表,模块等)。你可以动态地创建和销毁它们,把它们传递给其他函数,把它们作为值返回,等等。
本文使用Python 3.4.1版本
1.封装
你使用内层函数来保护它们不受函数外部变化的影响,也就是说把它们从全局作用域藏起来。
这里有一个简单的例子来强调这一概念:
1 2 3 4 5 6 7 8 |
def outer(num1): def inner_increment(num1): # hidden from outer code return num1 + 1 num2 = inner_increment(num1) print(num1, num2) inner_increment(10) # outer(10) |
尝试调用inner_increment()
函数
1 2 3 4 |
Traceback (most recent call last): File "inner.py", line 7, in <module> inner_increment() NameError: name 'inner_increment' is not defined |
现在,把inner_increment
的调用注释掉,再把对外部函数调用的注释取消,outer(10)
,把10作为参数传入:
1 |
10 11 |
请记住这仅仅是一个例子,尽管代码得到了期望的结果,但是使用一个前置的下划线把
inner_increment()
函数变为“私有”函数:_inner_increment()
更好。
下面这个递归的例子与使用嵌套函数相比稍微好一些:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def factorial(number): # error handling if not isinstance(number, int): raise TypeError("Sorry. 'number' must be an integer.") if not number >= 0: raise ValueError("Sorry. 'number' must be zero or positive.") def inner_factorial(number): if number <= 1: return 1 return number*inner_factorial(number-1) return inner_factorial(number) # call the outer function print(factorial(4)) |
同样测试一下这段代码。使用这种设计模式的一个主要优势在于:在外部函数中对全部参数执行了检查,你可以在内部函数中跳过全部的检查过程。
关于这个递归更加详细的解释请看Problem Solving with Algorithms and Data Structures
2.贯彻DRY(Don’t Repeat Yourself )原则
也许你有一个巨型函数,在很多很多地方执行一大段的代码。比如,你可能写了一个函数用来处理文件,并且你希望它既可以接受一个打开文件对象或是一个文件名:
1 2 3 4 5 6 7 8 9 |
def process(file_name): def do_stuff(file_process): for line in file_process: print(line) if isinstance(file_name, str): with open(file_name, 'r') as f: do_stuff(f) else: do_stuff(file_name) |
同样,通常会把
do_stuff()
作为一个顶层私有函数,但是如果你想要把它作为一个内层函数隐藏起来,你也可以这样做。
来个实际的例子怎么样?
让我们假设你想知道纽约市全部WiFi热点的数量。而且确实有提供这些信息的原始数据: 数据。
访问这个网站并下载CSV.
内层函数——它们的优点是什么?
让我们看一下写内层函数的三个常见原因。
记住:在Python中,函数是“一等公民”,这意味着它们和其他对象平起平坐(例如:整型,字符串,列表,模块等)。你可以动态地创建和销毁它们,把它们传递给其他函数,把它们作为值返回,等等。
本文使用Python 3.4.1版本
1.封装
你使用内层函数来保护它们不受函数外部变化的影响,也就是说把它们从全局作用域藏起来。
这里有一个简单的例子来强调这一概念:
1 2 3 4 5 6 7 8 |
def outer(num1): def inner_increment(num1): # hidden from outer code return num1 + 1 num2 = inner_increment(num1) print(num1, num2) inner_increment(10) # outer(10) |
尝试调用inner_increment()
函数
1 2 3 4 |
Traceback (most recent call last): File "inner.py", line 7, in <module> inner_increment() NameError: name 'inner_increment' is not defined |
现在,把inner_increment
的调用注释掉,再把对外部函数调用的注释取消,outer(10)
,把10作为参数传入:
1 |
10 11 |
请记住这仅仅是一个例子,尽管代码得到了期望的结果,但是使用一个前置的下划线把
inner_increment()
函数变为“私有”函数:_inner_increment()
更好。
下面这个递归的例子与使用嵌套函数相比稍微好一些:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
def factorial(number): # error handling if not isinstance(number, int): raise TypeError("Sorry. 'number' must be an integer.") if not number >= 0: raise ValueError("Sorry. 'number' must be zero or positive.") def inner_factorial(number): if number <= 1: return 1 return number*inner_factorial(number-1) return inner_factorial(number) # call the outer function print(factorial(4)) |
同样测试一下这段代码。使用这种设计模式的一个主要优势在于:在外部函数中对全部参数执行了检查,你可以在内部函数中跳过全部的检查过程。
关于这个递归更加详细的解释请看Problem Solving with Algorithms and Data Structures
2.贯彻DRY(Don’t Repeat Yourself )原则
也许你有一个巨型函数,在很多很多地方执行一大段的代码。比如,你可能写了一个函数用来处理文件,并且你希望它既可以接受一个打开文件对象或是一个文件名:
1 2 3 4 5 6 7 8 9 |
def process(file_name): def do_stuff(file_process): for line in file_process: print(line) if isinstance(file_name, str): with open(file_name, 'r') as f: do_stuff(f) else: do_stuff(file_name) |
同样,通常会把
do_stuff()
作为一个顶层私有函数,但是如果你想要把它作为一个内层函数隐藏起来,你也可以这样做。
来个实际的例子怎么样?
让我们假设你想知道纽约市全部WiFi热点的数量。而且确实有提供这些信息的原始数据: 数据。
访问这个网站并下载CSV.
现在,把inner_increment
的调用注释掉,再把对外部函数调用的注释取消,