我終於弄懂了Python的裝飾器(一)

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"此係列文檔:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.bigyoung.cn/posts/91/","title":""},"content":[{"type":"text","text":"1. 我終於弄懂了Python的裝飾器(一)"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.bigyoung.cn/posts/92/","title":""},"content":[{"type":"text","text":"2. 我終於弄懂了Python的裝飾器(二)"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.bigyoung.cn/posts/93/","title":""},"content":[{"type":"text","text":"3. 我終於弄懂了Python的裝飾器(三)"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https://www.bigyoung.cn/posts/94/","title":""},"content":[{"type":"text","text":"4. 我終於弄懂了Python的裝飾器(四)"}]}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"一、裝飾器基礎(什麼是裝飾器)"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"Python的函數是對象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要了解裝飾器,您必須首先了解函數是Python中的對象。這具有重要的聯繫。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"讓我們來看一個簡單的例子:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"def shout(word=\"yes\"):\nreturn word.capitalize()+\"!\"\nprint(shout())\n# 輸出 : 'Yes!'\n# 作爲一個對象,您可以像其他對象一樣將函數賦給變量\nscream = shout\n#注意我們不使用括號:我們沒有調用函數\n#我們將函數“shout”放入變量“scream”。\n#這意味着您可以從“scream”中調用“shout”:\nprint(scream())\n# 輸出: 'Yes!'\n#除此之外,這意味着您可以刪除舊名稱'shout',該功能仍可從'scream'訪問\ndel shout\ntry:\nprint(shout())\nexcept NameError as e:\nprint(e)\n#輸出: \"name 'shout' is not defined\"\nprint(scream())\n# 輸出: 'Yes!'"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"請記住這一點,我們將在不久後回頭再說。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Python函數的另一個有趣特性是可以在另一個函數中定義它們!"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"def talk():\n# 您可以在“talk”中動態定義一個函數...\ndef whisper(word=\"yes\"):\nreturn word.lower()+\"...\"\n# ...並且可以立馬使用它。\nprint(whisper())\n#您每次調用“talk”,都會定義“whisper”,然後在“talk”中調用“whisper”。\ntalk()\n# 輸出:\n# \"yes...\"\n# 但是\"whisper\"不存在\"talk\"定義以外的地方:\ntry:\nprint(whisper())\nexcept NameError as e:\nprint(e)\n#輸出 : \"name 'whisper' is not defined\""}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"函數參考"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"OK,應該還在看吧?現在開始有趣的部分..."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"您已經看到函數是對象。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此,函數:"}]},{"type":"bulletedlist","content":[{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以分配給變量"}]}]},{"type":"listitem","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以在另一個函數中定義"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這意味着**一個函數可以"},{"type":"codeinline","content":[{"type":"text","text":"return"}]},{"type":"text","text":"另一個功能**。"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"def getTalk(kind=\"shout\"):\n# 我們頂一個即時的函數\ndef shout(word=\"yes\"):\nreturn word.capitalize()+\"!\"\ndef whisper(word=\"yes\") :\nreturn word.lower()+\"...\";\n# 然後我們返回它\nif kind == \"shout\":\n#我們不使用“()”,所以我們沒有調用函數,我們正在返回這個函數對象\nreturn shout\nelse:\nreturn whisper\n#獲取函數並將其分配給變量: \"talk\"\ntalk = getTalk()\n#您可以看到“talk”是一個函數對象:\nprint(talk)\n#輸出 : \n#函數對象返回的內容:\nprint(talk())\n#輸出 : Yes!\n#如果您感到困惑,甚至可以直接使用它:\nprint(getTalk(\"whisper\")())\n#outputs : yes..."}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"還有更多的內容!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果可以"},{"type":"codeinline","content":[{"type":"text","text":"return"}]},{"type":"text","text":"一個函數,則可以將其中一個作爲參數傳遞:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"def doSomethingBefore(func):\nprint(\"I do something before then I call the function you gave me\")\nprint(func())\ndoSomethingBefore(scream)\n#輸出:\n#I do something before then I call the function you gave me\n#Yes!"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"好吧,您只具備瞭解裝飾器所需的所有信息。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"您會看到,裝飾器是“包裝器(wrappers)”,這意味着"},{"type":"text","marks":[{"type":"strong"}],"text":"它們使您可以在裝飾函數之前和之後執行代碼,"},{"type":"text","text":"而無需修改函數本身的代碼內容。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"手工進行裝飾"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"您將知道如何進行手動操作:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"#裝飾器是講另外一個函數作爲參數的函數\ndef my_shiny_new_decorator(a_function_to_decorate):\n# 在內部,裝飾器動態定義一個函數:包裝器(wrappers)。\n# 此功能將被包裝在原始功能的外部,以便它可以在代碼之前和之後執行代碼。\ndef the_wrapper_around_the_original_function():\n# 在調用原始函數之前,將要執行的代碼放在此處\nprint(\"Before the function runs\")\n#在此處調用函數(使用括號)\na_function_to_decorate()\n# 在調用原始函數後,將要執行的代碼放在此處\nprint(\"After the function runs\")\n#至此,“a_function_to_decorate”從未執行過。\n#我們返回剛剛創建的包裝函數。\n#包裝器包含函數和在代碼之前和之後執行的代碼。隨時可以使用!\nreturn the_wrapper_around_the_original_function\n#現在,假設您創建了函數,但是不想再修改的函數。\ndef a_stand_alone_function():\nprint(\"I am a stand alone function, don't you dare modify me\")\na_stand_alone_function()\n#輸出: I am a stand alone function, don't you dare modify me\n#所以,您可以裝飾它以擴展其行爲。\n#只需將其傳遞給裝飾器,它將動態地包裝在\n#您想要的任何代碼中,併爲您返回準備使用的新功能:\na_stand_alone_function_decorated = my_shiny_new_decorator(a_stand_alone_function)\na_stand_alone_function_decorated()\n#輸出:\n#Before the function runs\n#I am a stand alone function, don't you dare modify me\n#After the function runs"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在,您可能希望每次調用"},{"type":"codeinline","content":[{"type":"text","text":"a_stand_alone_function"}]},{"type":"text","text":"時"},{"type":"codeinline","content":[{"type":"text","text":"a_stand_alone_function_decorated"}]},{"type":"text","text":"都調用它。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這很簡單,只需"},{"type":"codeinline","content":[{"type":"text","text":"a_stand_alone_function"}]},{"type":"text","text":"用以下方法返回的函數覆蓋"},{"type":"codeinline","content":[{"type":"text","text":"my_shiny_new_decorator"}]},{"type":"text","text":":"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"a_stand_alone_function = my_shiny_new_decorator(a_stand_alone_function)\na_stand_alone_function()\n#輸出:\n#Before the function runs\n#I am a stand alone function, don't you dare modify me\n#After the function runs\n#這正是裝飾器的工作!"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"裝飾器神祕化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏展示一下使用裝飾器的語法:"}]},{"type":"codeblock","attrs":{"lang":"python"},"content":[{"type":"text","text":"@my_shiny_new_decorator\ndef another_stand_alone_function():\nprint(\"Leave me alone\")\nanother_stand_alone_function()\n#輸出:\n#Before the function runs\n#Leave me alone\n#After the function runs"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"是的,僅此而已。"},{"type":"codeinline","content":[{"type":"text","text":"@decorator"}]},{"type":"text","text":"只是實現以下目的的捷徑:"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"another_stand_alone_function = my_shiny_new_decorator(another_stand_alone_function)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"裝飾器只是"},{"type":"link","attrs":{"href":"http://en.wikipedia.org/wiki/Decorator_pattern","title":""},"content":[{"type":"text","text":"裝飾器設計模式"}]},{"type":"text","text":"的pythonic變體。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Python中嵌入了幾種經典的設計模式來簡化開發(例如迭代器)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然,您可以累加裝飾器:"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"def bread(func):\ndef wrapper():\nprint(\"''''''\\>\")\nfunc()\nprint(\"\")\nreturn wrapper\ndef ingredients(func):\ndef wrapper():\nprint(\"#tomatoes#\")\nfunc()\nprint(\"~salad~\")\nreturn wrapper\ndef sandwich(food=\"--ham--\"):\nprint(food)\nsandwich()\n#輸出: --ham--\nsandwich = bread(ingredients(sandwich))\nsandwich()\n#輸出:\n#''''''\\>\n# #tomatoes#\n# --ham--\n# ~salad~\n#"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用Python裝飾器語法:"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"@bread\n@ingredients\ndef sandwich(food=\"--ham--\"):\nprint(food)\nsandwich()\n#outputs:\n#''''''\\>\n# #tomatoes#\n# --ham--\n# ~salad~\n#"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"您設置裝飾器事項的順序是很重要的,如::"}]},{"type":"codeblock","attrs":{"lang":""},"content":[{"type":"text","text":"@ingredients\n@bread\ndef strange_sandwich(food=\"--ham--\"):\nprint(food)\nstrange_sandwich()\n#outputs:\n##tomatoes#\n#''''''\\>\n# --ham--\n#\n# ~salad~"}]},{"type":"blockquote","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文首發於BigYoung小站:"},{"type":"link","attrs":{"href":"http://www.bigyoung.cn","title":""},"content":[{"type":"text","text":"http://www.bigyoung.cn"}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章