iT邦幫忙

0

想問一下 這個 @ 是 python 標準語法嗎 ? 寫 line bot 時的小困惑

看不太懂 @ 這個語法 的意義
FLASK裡面好像用非常多
@app.route("/callback", methods=['POST'])
def callback():

@webhookhandler.add(MessageEvent, message=TextMessage)
def echo_msg(event):

請問上面這兩行有關係嗎

想問一下 這個 @ 是 python 標準語法嗎 ?
@是類似 c# 中的屬性符號嗎 [Athentication] ??
如果是的話 這種 @ 的東西要怎麼自己寫

@webhookhandler.add(MessageEvent, message=TextMessage)
這行白話文是什麼 ???

2 個回答

3
koro_michael
iT邦新手 3 級 ‧ 2021-03-29 14:33:58
最佳解答

https://medium.com/citycoddee/python%E9%80%B2%E9%9A%8E%E6%8A%80%E5%B7%A7-3-%E7%A5%9E%E5%A5%87%E5%8F%88%E7%BE%8E%E5%A5%BD%E7%9A%84-decorator-%E5%97%B7%E5%97%9A-6559edc87bc0

===========================

如果看一下 line python 的程式碼,可以看到以下這一段

class WebhookHandler(object):

    def add(self, event, message=None):
        def decorator(func):
            if isinstance(message, (list, tuple)):
                for it in message:
                    self.__add_handler(func, event, message=it)
            else:
                self.__add_handler(func, event, message=message)

            return func

        return decorator

用簡單的話解釋,就是把 def echo_msg(event) 傳進 WebhookHandler.add 中

===========================

一個簡單的範例

def foo(foo2):
    def helloWorld():
        print("Hello")
        foo2()
        print("World!")

    return helloWorld
    
@foo
def test1():
    print("test 1")
    
@foo
def test2():
    print("test 2")
    
test1()
test2()

執行結果

Hello
test 1
World!
Hello
test 2
World!

帶參數的

def foo(message):
    print(message)
    def helloWorld(foo2):
        print("Hello")
        foo2()
        print("World!")

    return helloWorld
    
@foo("A1")
def test1():
    print("test 1")
    
@foo("B1")
def test2():
    print("test 2")

執行結果

A1
Hello
test 1
World!
B1
Hello
test 2
World!

看更多先前的回應...收起先前的回應...

所以 那個 @是類似 c# 中的屬性TAG [Athentication] 差不多

2015evanotes我 C# 沒有用的那麼深,所以無法回答你到底是不是跟 TAG [Athentication] 一樣

但 python 的裝飾器用一個我之前常用的設計模式中的模板模式概念差不多,都是固定一個執行順序框架,再把其中不一樣的地方切出去,達到減省程式碼的目的

我有附上一個小範例,你可以參考看看

有 我有看懂 感謝 這個是個好東西

2015evanotes有幫助的話就請給個最佳解答吧~感謝/images/emoticon/emoticon41.gif

選囉 抱歉忘記了 一時太開心 /images/emoticon/emoticon08.gif

rofellos iT邦新手 5 級 ‧ 2021-03-30 13:58:41 檢舉

我試的結果 @foo("A1")這邊就執行了 後面test1無動作

rofellos拍謝,最後那兩行沒刪除到/images/emoticon/emoticon04.gif

如果你想要像第一種範例一樣手動呼叫才執行的話,還得要再多包一層

def foo(message):
    def helloWorld(foo2):
        def h():
            print(message)
            print("Hello")
            foo2()
            print("World!")
        return h

    return helloWorld
    
@foo("A1")
def test1():
    print("test 1")
    
@foo("B1")
def test2():
    print("test 2")

test1()
test2()
微笑 iT邦新手 4 級 ‧ 2021-03-30 15:32:12 檢舉

這算另類的callback地獄嗎/images/emoticon/emoticon56.gif

微笑應該是不至於啦,不過才兩三層而已WWW

1

關鍵字 @ 在 Python 中稱為 裝飾器(Decorator)

可以讓開發者包裝函式,賦予函式更多的能力

例如在函式執行前後加入一些操作或判斷

def log(func):
    def warp():
        print('寫入 log 紀錄')
        func()
    return warp

@log
def func():
    print('執行函式')

func()

# 寫入 log 紀錄
# 執行函式

@app.route("/callback", methods=['POST'])
def callback():

這段的意思是告訴框架,如果收到 /callback 來的請求,並且 http 方法是 POST 的話,就執行 callback() 這個函式,其實就是設定接收 linebot 訊息的入口。

@webhookhandler.add(MessageEvent, message=TextMessage)
def echo_msg(event):

這段是設定 文字訊息(TextMessage) 的處理函式,因為 line 傳過來的訊息格式很複雜且加密過,所以這部分會交由框架來處理,可以看到 callback() 內的這行。

...
handler.handle(body, signature)
...

這行程式會將 app.route 收到的 JSON 訊息轉給框架處理,處理後會根據我們註冊的 webhookhandler.add 再轉回我們的程式,這樣我們就不必自己處理複雜的加解密和訊息類型的分類。

@handler.add(MessageEvent, message=TextMessage)
def handle_message(event):
    # 處理文字訊息

@handler.add(MessageEvent, message=ImageMessage)
def handle_image(event):
    # 處理圖片訊息

@handler.add(MessageEvent, message=VideoMessage)
def handle_video(event):
    # 處理影片訊息

而 C# 的 屬性(Attribute) 則比較像標籤,可以將某種屬性額外的標記在類別、方法、或屬性上,它的底層是類別不是函式,例如 [HttpPost] 是一個繼承於 Attribute 的特殊類別。

[HttpPost]
public ActionResult Index()
{
    ...
}

public class HttpPostAttribute : HttpMethodAttribute
{
    public HttpPostAttribute();
    ...
}

最後 Attribute 內其實也可以寫函式,例如 ActionFilter

public class ActionFilter : Attribute, IActionFilter
{
    public void OnActionExecuting(ActionExecutingContext context)
    {
        // Action 執行前要做...
        ...
    }

    public void OnActionExecuted(ActionExecutedContext context)
    {
        // Action 執行後要做...
        ...
    }
}

裝飾器也有 Class Decorator

class log:
    def __init__(self, f):
        self.f = f
    def __call__(self, *args, **kwargs):
        print('寫入 log 紀錄')
        return self.f(*args, **kwargs)

@log
def func():
    print('執行函式')
 
func()

# 寫入 log 紀錄
# 執行函式

所以在底層的設計思路上,兩者是屬於不同的東西

但在使用上兩者還蠻相似的!!

╰( ̄▽ ̄)╭

我要發表回答

立即登入回答