Section 07 - Scopes, Closures and Decorators 番外篇

Scopes 作用域

Closures 閉包

Decorators 裝飾器


Python Scopes 作用域

網路上大部分是用 LEGB 的方式來描述 Scopes 作用域

Local → Enclosed → Global → Built-in


Decorators 裝飾器

Decorator 程式範例

1. Function-based Decorators

注意:註解中的數字是執行順序,下同。

# Decorator Function Sample
def logged(func):
    print('scope of logged') # 2 進入logged scope
    print("Entering function name is: {}".format(func.__name__)) # 3 
    def with_logging(*args, **kwargs):
        print('scope of with_logging') # 6
        print("Entering function name is: {}".format(func.__name__)) # 7
        print("arg:",*args) # 8
        print("kwarg:",**kwargs) # 9 
        result = func(*args, **kwargs) 
        print("Exited", func.__name__) # 11
        return result
    print('exit') # 4
    return with_logging
 
print('start using decorator') # 1
@logged # 呼叫logged
def test(k):
   print("execute k: {}".format(k)) # 10
   return k
 
print('execute') # 5
print(test(10)) # 12

輸出

start using decorator
scope of logged
Entering function name is: test
exit
excute
scope of with_logging
Entering function name is: test
arg: 10
kwarg:
execute k: 10
Exited test
10

2. Class-based Decorators

# Decorator Class Sample
class decorator(object):
 
    def __init__(self, f):
        print('enter init')
        self.f = f
        print('exit init')

    def __call__(self, *args, **kwargs):
        print("Entering", self.f.__name__)
        r = self.f(*args, **kwargs)
        print("Exited", self.f.__name__)
        return r
 
print('start decorator ')
 
@decorator
def hello(k):
    print('inside hello')
    return("k is: " + k)
 
print('excute')
print(hello('say hello!'))

輸出

start decorator 
enter init
exit init
excute
Entering hello
inside hello
Exited hello
k is: say hello!

3. 不帶參數的 Function-based Decorators

# 不帶參數的 Decorator Function
def decorator(f):
    print("excute  \"{}\"  decorate".format(f.__name__))
    def print_df(*args, **kargs):
        print("print_df before call")
        result = f(*args, **kargs) # 呼叫 hello(),並將回傳值傳遞給result
        print("print_df after call")
        print("印出回傳值: {}".format(result)) 
        return result
    return print_df
 
@decorator
def hello():
    print("say hello.")
    return "hello"

hello()

輸出

excute  "hello"  decorate
print_df before call
say hello.
print_df after call
印出回傳值: hello

4. 帶參數的 Function-based Decorators

# 帶有參數的 Decorator Function
def parseDecorator(param1, param2):
    print("excute 'parseDecorator'") # 解析parseDecorator內的參數
    def decorator(f):
        print("excute  \"{}\"  decorate".format(f.__name__))
        def print_df(*args, **kargs):
            print("params are: '{}', '{}' ".format(param1, param2))
            print("print_df before call")
            result = f(*args, **kargs) # 呼叫 hello(),並將回傳值傳遞給result
            print("print_df after call")
            print("印出回傳值: {}".format(result)) 
            return result
        return print_df
    return decorator
 
@parseDecorator("param1", "param2")
def hello():
    print("say hello.")
    return "hello"

hello()

輸出

excute 'parseDecorator'
excute  "hello"  decorate
params are: 'param1', 'param2' 
print_df before call
say hello.
print_df after call
印出回傳值: hello

5. 不帶參數的 Class-based Decorators

# 沒有參數的 Decorator Class
class decorator():
    def __init__(self, f): # 對參數、函式進行初始化
        self.f = f
    
    def __call__(self, *args, **kargs):
        print("person1 before call")
        result = self.f() # 呼叫 person1()獲得回傳值,並將回傳值assign給result
        print("result: {}".format(result)) # 印出回傳值
        print("person1 after call")
    
@decorator
def person1():
    print("I'm person1")
    return "person1"

person1()

輸出

person1 before call
I'm person1
result: person1
person1 after call

6. 帶參數的 Class-based Decorators

# 有參數的 Decorator Class
class decorateFruitClass(object):
    def __init__(self, fruit, amount):
        self.fruit = fruit
        self.amount = amount
 
    def __call__(self, f):
        def buy(*args, **kargs):
            print("%s %s before call" % (self.amount, self.fruit))
            result = f(*args, **kargs)
            print("%s %s after call" % (self.amount, self.fruit))
            return result
        return buy
 
@decorateFruitClass('guava', 10)
def person1():
    print("I'm  person1.")

@decorateFruitClass('banana', 20)
def person2():
    print("I'm  person2.")

person1()
print('-------')
person2()

輸出

10 guava before call
I'm  person1.
10 guava after call
-------
20 banana before call
I'm  person2.
20 banana after call

本文程式碼示範皆來自:Tsung Yu Chen (CC BY 4.0) ,非常感謝!

2 Likes

你找得這幾篇參考,感覺解釋得有稍難一些,我有找到兩篇,還能呼應到今天討論時,Oviler 兄提到的在 javascript 對 closure 的概念衍伸,提供參考:

  1. Python進階技巧 (4) — Lambda Function 與 Closure 之謎! | by Jack Cheng | 整個程式都是我的咖啡館 | Medium
  2. Python進階技巧 (3) — 神奇又美好的 Decorator ,嗷嗚! | by Jack Cheng | 整個程式都是我的咖啡館 | Medium
    這兩篇對 Closure 與 Decorator 講解非常淺顯易懂~
1 Like

感謝 Chris 兄分享,馬上拜讀!