First-class functions:在程式語言中,functions可以被當作是一個物件或變數。
因此,Python中的functions是first-class objects。並具有下列幾項功能:
指派到一個變數:
def hello():
print("Hello World")
greet = hello
greet()
--------------------------------------------------
# Hello World
可以將一個function當作另一個functions的參數(argument):
(The same idea from Calculus or discrete math - composite function.)
def hello():
print("Hello World")
def call_another_function(other_func):
# other_func = hello
other_func()
call_another_function(hello)
--------------------------------------------------
# Hello World
def square(num):
return num ** 2
my_list = [1, 2, 3, 4]
result = map(square, my_list)
for i in result:
print(i)
--------------------------------------------------
# 1
# 4
# 9
# 16
functions可以回傳一個function。
def hello():
def greet():
print("greet!!")
return greet
welcome = hello()
welcome()
--------------------------------------------------
# greet!!
def hello(name):
def greet(another_name):
print("hello, " + another_name)
def bye(another_name):
print("bye, " + another_name)
if name == "greet":
return greet
else:
return bye
welcome = hello("greet")
goodbye = hello("something else")
welcome("Wilson")
goodbye("Grace")
--------------------------------------------------
# hello, Wilson
# bye, grace
可以放入list、tuple或dictionary。
def hello():
print("hello 1")
def hello2():
print("hello 2")
for func in [hello, hello2]:
func()
--------------------------------------------------
# hello 1
# hello 2
在Python中,常會使用一個higher-order function將其他function包在裡面。使我們在執行該function的前後執行其他程式碼。
Example:
def new_decorator(original_func):
def wrap_func():
print("Here is some codes before the original function.")
original_func()
print("Here is some codes after the original function.")
return wrap_func
def func_needs_decorator():
print("I am a function that needs decorator.")
decorated_function = new_decorator(func_needs_decorator) # wrap_func(func_needs_decorator)
decorated_function()
--------------------------------------------------
# Here is some codes before the original function.
# I am a function that needs decorator.
# Here is some codes after the original function.
因為此作法太常見,因此Python提供一個名為decorator的語法糖來簡化這個過程。
Example:
def new_decorator(original_func):
def wrap_func():
print("Here is some codes before the original function.")
original_func()
print("Here is some codes after the original function.")
return wrap_func
@new_decorator # @ 後面接想要被哪個higher-order function包起來
def func_needs_decorator():
print("I am a function that need decorator.")
func_needs_decorator()
--------------------------------------------------
# Here is some codes before the original function.
# I am a function that needs decorator.
# Here is some codes after the original function.
Decorators在Python frameworks(其他人用Python寫的有用工具)中很常見。
例如:Flask就是一個Python framework,可以用來建立網頁伺服器(web server)。
若想建立一個網頁伺服器,傳統上要設定TCP和HTTP protocols(網際網路協議)。但在Flask中,可以直接使用Flask提供的decorator,快速建立一個網頁伺服器。
from flask import Flask
app = Flask(__name__)
@app.route("/hello")
def hello():
return "Hello World!"
if __name__ == "__main__":
app.run(debug=True)
Recall the generator syntax that we learned from chapter 3. (The one that is very similar to comprehension.)
yield
# for loop
def cube(n):
result = []
for x in range(n):
result.append(x ** 3)
return result
for i in cube(10):
print(i)
# disadvantage:
# result的長度越長,占用的記憶體位置越多。
# generator
def cube(n):
for x in range(n):
yield x ** 3
print(cube(10)) # <generator object cube at ...>
for element in cube(10):
print(element)
yield from
def sub_generator(x):
for i in range(x):
yield i ** 2
def gen(y):
yield from sub_generator(y)
for num in gen(15):
print(num)
使用情境:
def get_all_users(): # 可以取得所有使用者的id,但若想單獨取老師或學生
for id in get_teachers_id(): # 的部分,需要重新定義下列兩個函數。
yield id
for id in get_students_id():
yield id
def teacher_id_generator():
for i in get_teachers_id():
yield id
def student_id_generator():
for i in get_students_id():
yield id
def get_all_users(): # 主要用於協助重新架構程式碼,使程式碼更易於
yield from teacher_id_generator() # 維護,並減少重複的程式碼。
yield from student_id_generator()
def teacher_id_generator():
for i in get_teachers_id():
yield id
def student_id_generator():
for i in get_students_id():
yield id