我终于弄懂了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}}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章