本週作業與進度:
1. 研讀The Quick Python Book 3rd Ch9
2. f-string
3. Python: 裝飾器(decorator)
4. 研讀 Advanced R: Function operators
函數為 『一級物件(first-class object)』:
1. 可指派給變數
def yell(text):
return text.upper() + '!'
yell('hello')
## 'HELLO!'
bark = yell
bark('hello')
#
## 'HELLO!'
id(yell) # 查詢物件yell的内存位址
## 4620874344
id(bark) # 查詢物件bark的內存位址
## 4620874344
del yell # 移除掉yell標籤與此函數物件的連結
bark('hello') # 但bark標籤與此函數物件連結仍存在
## 'HELLO!'
bark.__name__
## 'yell'
(lambda x: x**2).__name__ ## 補充:lambda函數的name為lambda
## '<lambda>'
funcs = [bark, str.lower, str.capitalize]
funcs
## [<function yell at 0x1136cf268>, <method 'lower' of 'str' objects>, <method 'capitalize' of 'str' objects>]
funcs[1]('NCCU')
## 'nccu'
def greet(func):
greeting = func('Hi, I am a Python Program')
print(greeting)
def wisper(text):
return text.lower() + '...'
greet(bark)
## HI, I AM A PYTHON PROGRAM!
greet(funcs[2])
## Hi, i am a python program
greet(str.swapcase)
## hI, i AM A pYTHON pROGRAM
greet(wisper)
## hi, i am a python program...
list(map(bark, ['hello', 'hey', 'hi']))
## ['HELLO!', 'HEY!', 'HI!']
def speak(text):
def Whisper(t):
return t.lower() + '...'
return Whisper(text)
speak('Hello World')
## 'hello world...'
# Whisper('Yo')
# NameError: name 'Whisper' is not defined
def get_speak_func(volume):
def Whisper(text):
return text.lower() + '...'
def Yell(text):
return text.upper() + '!'
if volume > 0.5:
return Yell
else:
return Whisper
get_speak_func(0.3)
## <function get_speak_func.<locals>.Whisper at 0x11368d048>
get_speak_func(0.7)('Hello')
## 'HELLO!'
def get_speak_func(volume, text):
def Whisper():
return text.lower() + '...'
def Yell():
return text.upper() + '!'
if volume > 0.5:
return Yell
else:
return Whisper
func = get_speak_func(volume=0.7, text='Hello, World')
func() # 記住了父函數參數text值
## 'HELLO, WORLD!'
def power(exponent):
def f(x):
return x ** exponent
return f
square = power(2)
cubic = power(3)
x = square(3)
x
## 9
y = cubic(3)
y
## 27
callable(square)
## True
callable(x)
## False
def counter():
i = 0
def count():
nonlocal i
i = i + 1
return i
return count
counter_one = counter()
counter_one()
## 1
counter_one()
## 2
counter_two = counter()
counter_two()
## 1
counter_two()
## 2
counter_two()
## 3
new_counter <- function() {
i <- 0
function() {
i <<- i + 1
i
}
}
counter_1 = new_counter()
counter_1()
## [1] 1
counter_1()
## [1] 2
def add1(x, y):
return x + y
add2 = lambda x, y: x + y
add1(1, 2)
## 3
add2(1, 2)
## 3
(lambda x, y: x + y)('A', 'B')
## 'AB'
l = ['d', 'b', 'c', 'a']
tuples_list = list(enumerate(l))
tuples_list
## [(0, 'd'), (1, 'b'), (2, 'c'), (3, 'a')]
sorted(tuples_list)
## [(0, 'd'), (1, 'b'), (2, 'c'), (3, 'a')]
sorted(tuples_list, key = lambda x: x[1])
## [(3, 'a'), (1, 'b'), (2, 'c'), (0, 'd')]
sorted(range(-5, 6), key = lambda x: x ** 2)
## [0, -1, 1, -2, 2, -3, 3, -4, 4, -5, 5]
def make_adder(n):
return lambda x: x + n
plus_3 = make_adder(3)
plus_3(5)
## 8
action = (lambda x: (lambda y: x + y))
act = action("99")
act("3")
## '993'
list(filter(lambda x: x % 2 == 0, range(16))) # 不好的寫法
## [0, 2, 4, 6, 8, 10, 12, 14]
[x for x in range(16) if x % 2 == 0] # 較好的寫法
## [0, 2, 4, 6, 8, 10, 12, 14]
from functools import reduce
reduce(lambda x, y: x + y, ['a', 'b', 'c', ])
## 'abc'
def my_reduce(function, sequence):
tally = sequence[0]
for next in sequence[1:]:
tally = function(tally, next)
return tally
my_reduce(lambda x, y: x * y, [2, 4, 6, 8])
## 384
一般來說用途可有以下情形:
def null_decorator(f):
return f
def greet():
return 'Hello'
greet = null_decorator(greet)
greet()
## 'Hello'
@null_decorator
def greet2():
return 'Hello'
greet2()
## 'Hello'
def decorate(func):
def wrapper_func(*args):
print('原函數執行前')
func(*args)
print('原函數已執行')
return wrapper_func
@decorate
def myfun(parameter):
print(parameter)
myfun('Hello')
## 原函數執行前
## Hello
## 原函數已執行
def uppercase(func):
def wrapper():
original_result = func()
modified_result = original_result.upper()
return modified_result
return wrapper
@uppercase
def greet3():
return 'Hello'
greet3
## <function uppercase.<locals>.wrapper at 0x1136a2a60>
greet3()
## 'HELLO'
def proxy(func):
def wrapper(*args, **kwargs): # 打包用
return func(*args, **kwargs) # 解包用
def trace(func):
def wrapper(*args, **kwargs):
# 使用f-string
print(f'追蹤: 呼叫函數 {func.__name__}, 參數為 {args}, {kwargs}')
original_result = func(*args, **kwargs)
print(f'追蹤: 函數 {func.__name__}, 傳回 {original_result!r}')
return original_result
return wrapper
@trace
def say(name, line):
return f'{name}: {line}'
say('同學', '早安')
## 追蹤: 呼叫函數 say, 參數為 ('同學', '早安'), {}
## 追蹤: 函數 say, 傳回 '同學: 早安'
## '同學: 早安'
import time
def timer(func):
def wrapper(*args, **kwargs):
start = time.perf_counter() # 紀錄開始時間
value = func(*args, **kwargs)
end = time.perf_counter() # 紀錄結束時間
run_time = end - start
print(f'函數 {func.__name__} 執行時間為 {run_time} 秒')
return value
return wrapper
@timer
def waste_some_time(n):
for _ in range(n):
sum([i for i in range(10000)])
waste_some_time(1000)
## 函數 waste_some_time 執行時間為 0.3759743550000001 秒
import functools
@timer
def myfun(n):
functools.reduce(lambda x, y: x + y, n)
myfun([1, 2, 3, 4, 5, ])
## 函數 myfun 執行時間為 5.021999999854643e-06 秒
def emphasis_1(func):
def wrapper():
return '( ' + func() + ' )'
return wrapper
def emphasis_2(func):
def wrapper():
return '{ ' + func() + ' }'
return wrapper
@emphasis_2
@emphasis_1
def greet():
return 'Hello!'
greet()
## '{ ( Hello! ) }'
def greet():
'''說明:傳回友善的問候'''
return '哈囉~'
decorated_greet = uppercase(greet)
greet.__name__ # 取得原始函數的名稱
## 'greet'
greet.__doc__ # 取得原始函數的文件字串
## '說明:傳回友善的問候'
decorated_greet.__name__ # 取得修飾函數的名稱(被換掉)
## 'wrapper'
decorated_greet.__doc__ # # 取得修飾函數的文件字串(被換掉為None)
import functools
def uppercase(func):
@functools.wraps(func)
def wrapper():
return func().upper()
return wrapper
@uppercase
def greet():
'''說明:傳回友善的問候'''
return '哈囉~'
greet.__name__
## 'greet'
greet.__doc__
## '說明:傳回友善的問候'
import functools
def uppercase_repeat(n):
def uppercase(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
result = func(*args, **kwargs)
result = result.upper()
for _ in range(n):
print(result)
return result
return wrapper
return uppercase
@uppercase_repeat(5)
def say(text):
return text
say('Good morning, Bob!')
## GOOD MORNING, BOB!
## GOOD MORNING, BOB!
## GOOD MORNING, BOB!
## GOOD MORNING, BOB!
## GOOD MORNING, BOB!
## 'GOOD MORNING, BOB!'