{"action":"opened","issue":{"url":"https://api.github.com/repos/loadlj/blog/issues/6","repository_url":"https://api.github.com/repos/loadlj/blog","labels_url":"https://api.github.com/repos/loadlj/blog/issues/6/labels{/name}","comments_url":"https://api.github.com/repos/loadlj/blog/issues/6/comments","events_url":"https://api.github.com/repos/loadlj/blog/issues/6/events","html_url":"https://github.com/loadlj/blog/issues/6","id":189063912,"number":6,"title":"Pyhton 装饰器和闭包","user":{"login":"loadlj","id":10071724,"avatar_url":"https://avatars.githubusercontent.com/u/10071724?v=3","gravatar_id":"","url":"https://api.github.com/users/loadlj","html_url":"https://github.com/loadlj","followers_url":"https://api.github.com/users/loadlj/followers","following_url":"https://api.github.com/users/loadlj/following{/other_user}","gists_url":"https://api.github.com/users/loadlj/gists{/gist_id}","starred_url":"https://api.github.com/users/loadlj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/loadlj/subscriptions","organizations_url":"https://api.github.com/users/loadlj/orgs","repos_url":"https://api.github.com/users/loadlj/repos","events_url":"https://api.github.com/users/loadlj/events{/privacy}","received_events_url":"https://api.github.com/users/loadlj/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":0,"created_at":"2016-11-14T09:25:43Z","updated_at":"2016-11-14T09:25:43Z","closed_at":null,"body":"# Pyhton 装饰器和闭包\r\n\r\n## 闭包(closure)\r\n\r\n了解闭包就先得了解nested function, 所谓嵌套函数从字面上就可以理解，一个简单例子。往简单了说就是返回一个函数，然后再去调用这个函数。\r\n\r\n```\r\ndef print_msg(msg):\r\n    \"\"\"This is the outer enclosing function\"\"\"\r\n\r\n    def printer():\r\n        \"\"\"This is the nested function\"\"\"\r\n        print(msg)\r\n\r\n    return printer  # this got changed\r\n\r\n# Now let's try calling this function.\r\n# Output: Hello\r\nanother = print_msg(\"Hello\")\r\nprint another\r\nanother()\r\n```\r\noutput\r\n\r\n```\r\n<function printer at 0x10bd9b758>\r\nHello\r\n```\r\n使用时有几个注意事项:\r\n\r\n* 必须要有一个嵌套函数\r\n* 嵌套函数里边必须要与其封闭函数中的一个变量相关联(否则闭包就没有意义了)\r\n* 封闭函数需要返回嵌套函数\r\n\r\n再来一个带参数的例子\r\n\r\n```\r\ndef make_inc(x):\r\n\tdef inc(y):\r\n    \t# x is \"closed\" in the definition of inc\r\n    \treturn y + x\r\n\treturn inc\r\nmake_3 = make_inc(3)\r\nmake_4 = make_inc(4)\r\nprint make_3(1)\r\nprint make_4(1)\r\n```\r\n\r\noutput\r\n\r\n```\r\n4\r\n5\r\n```\r\n\r\n## 装饰器(decorator)\r\n装饰器说白了就是把一个函数当成参数传到嵌套函数里边去，举个简单的例子\r\n\r\n```\r\ndef my_decorator(some_function):\r\n\r\n    def wrapper():\r\n\r\n        num = 10\r\n\r\n        if num == 10:\r\n            print(\"Yes!\")\r\n        else:\r\n            print(\"No!\")\r\n\r\n        some_function()\r\n\r\n        print(\"Something is happening after some_function() is called.\")\r\n\r\n    return wrapper\r\n\r\n\r\ndef just_some_function():\r\n    print(\"Wheee!\")\r\n\r\njust_some_function = my_decorator(just_some_function)\r\n\r\njust_some_function()\r\n```\r\n\r\noutput\r\n\r\n```\r\nYes!\r\nWheee!\r\nSomething is happening after some_function() is called.\r\n```\r\n\r\n当然，Pyhton里边有个语法糖，也可以这么写\r\n\r\n```\r\ndef my_decorator(some_function):\r\n\r\n    def wrapper():\r\n\r\n        num = 10\r\n\r\n        if num == 10:\r\n            print(\"Yes!\")\r\n        else:\r\n            print(\"No!\")\r\n\r\n        some_function()\r\n\r\n        print(\"Something is happening after some_function() is called.\")\r\n\r\n    return wrapper\r\n\r\n@my_decorator\r\ndef just_some_function():\r\n    print(\"Wheee!\")\r\n\r\n\r\njust_some_function()\r\n```\r\n\r\noutput\r\n\r\n```\r\nYes!\r\nWheee!\r\nSomething is happening after some_function() is called.\r\n```\r\n可以看到输出的结果是一样的。\r\n\r\n再来看一看常用的functools.wraps, 还是用上面的例子来测试\r\n\r\n```\r\ndef my_decorator(some_function):\r\n    def wrapper():\r\n\r\n        num = 10\r\n\r\n        if num == 10:\r\n            print(\"Yes!\")\r\n        else:\r\n            print(\"No!\")\r\n\r\n        some_function()\r\n\r\n        print(\"Something is happening after some_function() is called.\")\r\n\r\n    return wrapper\r\n\r\n@my_decorator\r\ndef just_some_function():\r\n    print(\"Wheee!\")\r\n\r\n\r\njust_some_function()\r\nprint just_some_function.__name__\r\n```\r\noutput\r\n\r\n```\r\nYes!\r\nWheee!\r\nSomething is happening after some_function() is called.\r\nwrapper\r\n```\r\n可以看到，当我门调用just_some_function时，其函数名称改变了，因为我门在调用时相当于做了这么个转换\r\n\r\n```\r\njust_some_function = my_decorator(just_some_function)\r\n```\r\n要想保留原始的函数信息需要用到`functools.wraps`\r\n\r\n```\r\ndef my_decorator(some_function):\r\n\timport functools\r\n\t@functools.wraps(some_function)\r\n    def wrapper():\r\n\r\n        num = 10\r\n\r\n        if num == 10:\r\n            print(\"Yes!\")\r\n        else:\r\n            print(\"No!\")\r\n\r\n        some_function()\r\n\r\n        print(\"Something is happening after some_function() is called.\")\r\n\r\n    return wrapper\r\n\r\n@my_decorator\r\ndef just_some_function():\r\n    print(\"Wheee!\")\r\n\r\n\r\njust_some_function()\r\nprint just_some_function.__name__\r\n```\r\n\r\noutput \r\n\r\n```\r\nYes!\r\nWheee!\r\nSomething is happening after some_function() is called.\r\nwrapper\r\n```\r\n`functools.wraps`具体信息可参考[so](http://stackoverflow.com/questions/308999/what-does-functools-wraps-do)\r\n\r\n装饰器叠加:\r\n\r\n```\r\ndef my_decorator(some_function):\r\n\t@functools.wraps(some_function)\r\n    def wrapper(num):\r\n    \t print(\"calling my_decorator\")\r\n        return some_function(num)\r\n    return wrapper\r\n\r\ndef another_decorator(some_function):\r\n\t@functools.wraps(some_function)\r\n\tdef wrapper(num):\r\n\t\tprint(\"calling another_decorator\")\r\n\t\treturn some_function(num)\r\n\treturn wrapper\r\n\r\n@my_decorator\r\n@another_decorator\r\ndef just_some_function(num):\r\n    return num * 2\r\n\r\n\r\nprint just_some_function(1)\r\n```\r\n\r\noutput\r\n\r\n```\r\ncalling my_decorator\r\ncalling another_decorator\r\n2\r\n```"}}
{"actor":{"display_login":"loadlj"}}