├── requirements.txt ├── .gitignore ├── doc2md2.pyc ├── Pipfile ├── test_doc2md2.py ├── .travis.yml ├── README.md ├── README.rst ├── setup.py ├── doc2md2.py ├── main ├── doc2md2.ipynb └── .ipynb_checkpoints │ ├── doc2md-checkpoint.ipynb │ └── markdown_md-checkpoint.ipynb ├── .vscode └── launch.json └── 让你的Python优雅.md /requirements.txt: -------------------------------------------------------------------------------- 1 | twine==1.9.1 2 | pytest==3.2.2 -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .pypirc 2 | build 3 | dist 4 | doc2md2.egg-info/* 5 | .cache/* -------------------------------------------------------------------------------- /doc2md2.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/chinanf-boy/doc2md/master/doc2md2.pyc -------------------------------------------------------------------------------- /Pipfile: -------------------------------------------------------------------------------- 1 | [[source]] 2 | url = "https://pypi.python.org/simple" 3 | verify_ssl = true 4 | name = "pypi" 5 | 6 | [packages] 7 | 8 | [dev-packages] 9 | 10 | pytest = "*" 11 | twine = "*" -------------------------------------------------------------------------------- /test_doc2md2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from doc2md2 import is_en_zh 3 | from doc2md2 import is_zh 4 | 5 | 6 | # import path, sys 7 | # import folder = path.path(__file__).abspath() 8 | # sys.path.append(folder.parent.parent) 9 | def test_en_zh(): 10 | assert is_en_zh(u"你好") <= 0 11 | assert is_en_zh(u"你好asdfsdf") > 0 12 | assert is_en_zh(u"helloworld 你好") > 0 13 | 14 | def test_zh(): 15 | assert is_zh(u"你好") is True 16 | assert is_zh(u"helloworld") is False 17 | assert is_zh(u"你helloworld好") is False 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.4" 5 | - "3.5" 6 | - "3.6" 7 | # - "pypy" # too many cache issues 8 | # - "3.7-dev" # no need, slows down builds 9 | # - "pypy3" # TODO: pkg_config issues 10 | 11 | # command to install dependencies 12 | install: 13 | - "pip install -e . --upgrade" 14 | - "pip install -r requirements.txt" 15 | 16 | # command to run the dependencies 17 | script: 18 | - "pytest " 19 | 20 | # command to run tests 21 | # jobs: 22 | # include: 23 | # - stage: "✨ Flake8 Nit–Picking ✨" 24 | # python: "3.6" 25 | # script: "pipenv run flake8" -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # doc2md 2 | 3 | [![Build Status](https://travis-ci.org/chinanf-boy/doc2md.svg?branch=master)](https://travis-ci.org/chinanf-boy/doc2md) 4 | 5 | 本意是为了 6 | 7 | 像 8 | 9 | --- 10 | 11 | ``` py 12 | 倒序 13 | for color in sorted(colors, reverse=True): 14 | print colors 15 | 16 | 自定义排序顺序 17 | 18 | colors = ['red', 'green', 'blue', 'yellow'] 19 | 20 | def compare_length(c1, c2): 21 | if len(c1) < len(c2): return -1 22 | if len(c1) > len(c2): return 1 23 | return 0 24 | 25 | print sorted(colors, cmp=compare_length) 26 | 27 | 更好的方法 28 | 29 | print sorted(colors, key=len) 30 | 31 | 第一种方法效率低而且写起来很不爽。另外,Python 3已经不支持比较函数了。 32 | 33 | 调用一个函数直到遇到标记值 34 | 35 | blocks = [] 36 | while True: 37 | block = f.read(32) 38 | if block == '': 39 | break 40 | blocks.append(block) 41 | ``` 42 | # 变成 下面 markdown 格式 43 | ``` py 44 | # 倒序 45 | for color in sorted(colors, reverse=True): 46 | print colors 47 | 48 | ``` 49 | 自定义排序顺序 50 | 51 | ``` py 52 | colors = ['red', 'green', 'blue', 'yellow'] 53 | 54 | def compare_length(c1, c2): 55 | if len(c1) < len(c2): return -1 56 | if len(c1) > len(c2): return 1 57 | return 0 58 | 59 | print sorted(colors, cmp=compare_length) 60 | 61 | ``` 62 | 更好的方法 63 | 64 | ``` py 65 | print sorted(colors, key=len) 66 | 67 | ``` 68 | 第一种方法效率低而且写起来很不爽。另外,Python 3已经不支持比较函数了。 69 | 70 | 调用一个函数直到遇到标记值 71 | 72 | ``` py 73 | blocks = [] 74 | while True: 75 | block = f.read(32) 76 | if block == '': 77 | break 78 | blocks.append(block) 79 | 80 | ``` 81 | 82 | --- 83 | 84 | ## 运行文件是 ``main/doc2md.py`` 85 | 86 | 一步一步过程 可以使用``jupyter notebook`` 查看 ``doc2md.ipynb`` 87 | 88 | 首先说明缺陷就是,命令行还没有做 89 | 请自己进入文件修改先。 90 | ``` py 91 | Path = "../让你的Python优雅.md" 92 | write_file = '../test_w.md' 93 | ``` 94 | 95 | 96 | ## demo 就是 97 | 98 | ``` py 99 | python doc2md.py file1 100 | ``` 101 | > 获取 ``让你的Python优雅.md`` 102 | 103 | > md格式``写``入 ``test_w.md`` 104 | 105 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | doc2md 2 | ====== 3 | 4 | .. image:: https://travis-ci.org/chinanf-boy/doc2md.svg?branch=master 5 | :target: https://travis-ci.org/chinanf-boy/doc2md 6 | 7 | 本意是为了 8 | 9 | 像 10 | 11 | -------------- 12 | 13 | .. code:: py 14 | 15 | 倒序 16 | for color in sorted(colors, reverse=True): 17 | print colors 18 | 19 | 自定义排序顺序 20 | 21 | colors = ['red', 'green', 'blue', 'yellow'] 22 | 23 | def compare_length(c1, c2): 24 | if len(c1) < len(c2): return -1 25 | if len(c1) > len(c2): return 1 26 | return 0 27 | 28 | print sorted(colors, cmp=compare_length) 29 | 30 | 更好的方法 31 | 32 | print sorted(colors, key=len) 33 | 34 | 第一种方法效率低而且写起来很不爽。另外,Python 3已经不支持比较函数了。 35 | 36 | 调用一个函数直到遇到标记值 37 | 38 | blocks = [] 39 | while True: 40 | block = f.read(32) 41 | if block == '': 42 | break 43 | blocks.append(block) 44 | 45 | 变成 下面 markdown 格式 46 | ======================= 47 | 48 | .. code:: py 49 | 50 | # 倒序 51 | for color in sorted(colors, reverse=True): 52 | print colors 53 | 54 | 自定义排序顺序 55 | 56 | .. code:: py 57 | 58 | colors = ['red', 'green', 'blue', 'yellow'] 59 | 60 | def compare_length(c1, c2): 61 | if len(c1) < len(c2): return -1 62 | if len(c1) > len(c2): return 1 63 | return 0 64 | 65 | print sorted(colors, cmp=compare_length) 66 | 67 | 更好的方法 68 | 69 | .. code:: py 70 | 71 | print sorted(colors, key=len) 72 | 73 | 第一种方法效率低而且写起来很不爽。另外,Python 3已经不支持比较函数了。 74 | 75 | 调用一个函数直到遇到标记值 76 | 77 | .. code:: py 78 | 79 | blocks = [] 80 | while True: 81 | block = f.read(32) 82 | if block == '': 83 | break 84 | blocks.append(block) 85 | 86 | -------------- 87 | 88 | 运行文件是 ``main/doc2md.py`` 89 | ----------------------------- 90 | 91 | 一步一步过程 可以使用\ ``jupyter notebook`` 查看 ``doc2md.ipynb`` 92 | 93 | 首先说明缺陷就是,命令行还没有做 请自己进入文件修改先。 94 | 95 | .. code:: py 96 | 97 | Path = "../让你的Python优雅.md" 98 | write_file = '../test_w.md' 99 | 100 | demo 就是 101 | --------- 102 | 103 | .. code:: py 104 | 105 | useag: 106 | $ doc2md2 file1 file2 107 | file2.md is create markdown from file1.md 108 | 109 | $ doc2md2 file1 110 | file1.md is create markdown from file1 111 | 112 | 113 | 获取 ``让你的Python优雅.md`` 114 | 115 | md格式\ ``写``\ 入 ``test_w.md`` 116 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Note: To use the 'upload' functionality of this file, you must: 5 | # $ pip install twine 6 | 7 | import io 8 | import os 9 | import sys 10 | from shutil import rmtree 11 | 12 | from setuptools import setup, Command 13 | 14 | # Package meta-data. 15 | NAME = 'doc2md2' 16 | DESCRIPTION = 'doc to markdown ' 17 | URL = 'https://github.com/kennethreitz/background' 18 | EMAIL = 'yobrave86550129@yahoo.com' 19 | AUTHOR = 'yobrave' 20 | VERSION = '0.1.3' 21 | 22 | # What packages are required for this module to be executed? 23 | REQUIRED = [ 24 | "termcolor" 25 | # 'requests', 'maya', 'records', 26 | ] 27 | 28 | # The rest you shouldn't have to touch too much :) 29 | # ------------------------------------------------ 30 | # Except, perhaps the License and Trove Classifiers! 31 | 32 | here = os.path.abspath(os.path.dirname(__file__)) 33 | 34 | # Import the README and use it as the long-description. 35 | # Note: this will only work if 'README.rst' is present in your MANIFEST.in file 36 | with io.open(os.path.join(here, 'README.rst'), encoding='utf-8') as f: 37 | long_description = '\n' + f.read() 38 | 39 | 40 | class PublishCommand(Command): 41 | """Support setup.py publish.""" 42 | 43 | description = 'Build and publish the package.' 44 | user_options = [] 45 | 46 | @staticmethod 47 | def status(s): 48 | """Prints things in bold.""" 49 | print('\033[1m{0}\033[0m'.format(s)) 50 | 51 | def initialize_options(self): 52 | pass 53 | 54 | def finalize_options(self): 55 | pass 56 | 57 | def run(self): 58 | try: 59 | self.status('Removing previous builds…') 60 | rmtree(os.path.join(here, 'dist')) 61 | except FileNotFoundError: 62 | pass 63 | 64 | self.status('Building Source and Wheel (universal) distribution…') 65 | os.system( 66 | '{0} setup.py sdist bdist_wheel --universal'.format(sys.executable)) 67 | 68 | self.status('Uploading the package to PyPi via Twine…') 69 | os.system('twine upload dist/* ') 70 | 71 | sys.exit() 72 | 73 | 74 | # Where the magic happens: 75 | setup( 76 | name=NAME, 77 | version=VERSION, 78 | description=DESCRIPTION, 79 | long_description=long_description, 80 | author=AUTHOR, 81 | author_email=EMAIL, 82 | url=URL, 83 | # If your package is a single module, use this instead of 'packages': 84 | py_modules=['doc2md2'], 85 | 86 | entry_points={ 87 | 'console_scripts': ['doc2md2=doc2md2:main'], 88 | }, 89 | 90 | install_requires=REQUIRED, 91 | include_package_data=True, 92 | license='ISC', 93 | classifiers=[ 94 | # Trove classifiers 95 | # Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers 96 | # 'License :: OSI Approved :: MIT License', 97 | 'Programming Language :: Python', 98 | 'Programming Language :: Python :: 2.6', 99 | 'Programming Language :: Python :: 2.7', 100 | 'Programming Language :: Python :: 3', 101 | 'Programming Language :: Python :: 3.3', 102 | 'Programming Language :: Python :: 3.4', 103 | 'Programming Language :: Python :: 3.5', 104 | 'Programming Language :: Python :: 3.6', 105 | 'Programming Language :: Python :: Implementation :: CPython', 106 | 'Programming Language :: Python :: Implementation :: PyPy' 107 | ], 108 | # $ setup.py publish support. 109 | cmdclass={ 110 | 'publish': PublishCommand, 111 | }, 112 | ) 113 | -------------------------------------------------------------------------------- /doc2md2.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | from __future__ import print_function 3 | from termcolor import cprint 4 | import re 5 | import sys 6 | import os 7 | 8 | # 全局 代码区域定义 9 | 10 | 11 | def py_is_fun(vv): 12 | global py_is 13 | if vv == '``` py': 14 | py_is = True 15 | 16 | elif vv == '```': 17 | py_is = False 18 | 19 | 20 | def input_w(file, value): 21 | file.write('\n' + value + '\n') 22 | 23 | # 匹配中文 24 | 25 | 26 | def is_zh(line): 27 | xx = u"([\u4e00-\u9fff]+)" 28 | pattern = re.compile(xx) 29 | results = pattern.findall(line) 30 | print(results) 31 | return bool(results) and (len(results[0]) == len(line)) 32 | # 匹配中英文 33 | 34 | 35 | def is_en_zh(line): 36 | xx = u"([\u4e00-\u9fff]+)" 37 | ch_pat = re.compile(xx) 38 | en_pat = re.compile('[a-zA-Z]+') 39 | ch_words = ch_pat.findall(line) 40 | en_words = en_pat.findall(line) 41 | 42 | return len(ch_words) and len(en_words) 43 | 44 | 45 | global py_is 46 | py_is = False 47 | 48 | 49 | def main(): 50 | input_value = { 51 | 'h2': "## ", 52 | 'start_tcode': "``` py\n", 53 | 'end_code': '```\n' 54 | } 55 | 56 | # 获得 文本文字 57 | try: 58 | Path = sys.argv[1] 59 | mkfileopen = open(Path) 60 | lines = mkfileopen.readlines() 61 | mkfileopen.close() 62 | except Exception as identifier: 63 | helpput = """useag: 64 | $ doc2md2 file1 file2 65 | file2.md is create markdown from file1.md 66 | 67 | $ doc2md2 file1 68 | file1.md is create markdown from file1 69 | """ 70 | return print(helpput) 71 | 72 | # 不需要改变,直接写入,开头匹配 73 | res = [r"``` py", r"更好的方法", r"#", r"```", r'---', ''] 74 | match_value_s = [] 75 | 76 | for k, line in enumerate(lines): 77 | line = line.decode('utf-8') 78 | for re_value in res: 79 | if line.isspace(): 80 | # \n 换行 直接 插入 81 | # print('直接原文空格\n',) 82 | match_value_s.append(line) 83 | break 84 | 85 | match_value = re.match(re_value, line.strip(), re.M | re.I) 86 | 87 | if match_value: 88 | 89 | # 代码开始—结束的区域固定 90 | # ``` py 91 | # ``` 92 | # print('两个```py 代码', line) 93 | if py_is and re_value == r'``` py': 94 | match_value_s.append(input_value['end_code'] + line) 95 | py_is_fun('```') 96 | break 97 | elif re_value == r'``` py': 98 | py_is_fun(re_value) 99 | # print('本来开始代码', line) 100 | match_value_s.append(line) 101 | break 102 | elif re_value == r'```': 103 | # print('本来结束代码', line) 104 | match_value_s.append(line) 105 | py_is_fun('```') 106 | break 107 | elif py_is: 108 | # print('其他白名单前代码闭合', line) 109 | match_value_s.append(input_value['end_code'] + line) 110 | py_is_fun('```') 111 | break 112 | else: 113 | # print('原文白名单', line) 114 | match_value_s.append(line) 115 | break 116 | 117 | else: 118 | 119 | # 有中文有英文,不做处理 120 | # 多个中文片段 121 | if is_en_zh(line) is not 0 or is_zh(line) > 1: 122 | if py_is: 123 | match_value_s.append(input_value['end_code'] + line) 124 | # print('end', line) 125 | py_is_fun('```') 126 | 127 | else: 128 | # print('原本中文或英文不用加', line) 129 | match_value_s.append(line) 130 | 131 | # 单个中文片段,加 h2 132 | elif is_zh(line) and is_zh(line) <= 1: 133 | if py_is: 134 | match_value_s.append( 135 | input_value['end_code'] + input_value['h2'] + line) 136 | # print('加h2+end', line) 137 | py_is_fun('```') 138 | 139 | else: 140 | # print('加h2', line) 141 | match_value_s.append(input_value['h2'] + line) 142 | # 默认 143 | elif py_is is False: 144 | 145 | match_value_s.append(input_value['start_tcode'] + line) 146 | # print('start', str(k), repr(line)) 147 | py_is_fun('``` py') 148 | 149 | else: 150 | # print('默认原文', line) 151 | match_value_s.append(line) 152 | 153 | if py_is is True: 154 | match_value_s.append('\n' + input_value['end_code']) 155 | 156 | try: 157 | if len(sys.argv) > 2: 158 | write_file = sys.argv[2] 159 | else: 160 | write_file = Path 161 | 162 | if write_file.find('md') <= 0: 163 | write_file = write_file + '.md' 164 | 165 | file = open(write_file, 'w+') 166 | for i in match_value_s: 167 | file.write(i) 168 | file.close() 169 | 170 | output = "< {} >file is create markdown from < {} >".format( 171 | write_file, Path) 172 | cprint(output, 'green') 173 | 174 | except Exception as identifier: 175 | raise Exception(write_file, 'error', identifier) 176 | 177 | 178 | if __name__ == '__main__': 179 | main() 180 | -------------------------------------------------------------------------------- /main/doc2md2.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "from __future__ import print_function\n", 12 | "from termcolor import cprint\n", 13 | "import re\n", 14 | "import sys\n", 15 | "import os\n", 16 | "\n", 17 | "# 全局 代码区域定义\n", 18 | "\n", 19 | "\n", 20 | "def py_is_fun(vv):\n", 21 | " global py_is\n", 22 | " if vv == '``` py':\n", 23 | " py_is = True\n", 24 | "\n", 25 | " elif vv == '```':\n", 26 | " py_is = False\n", 27 | "\n", 28 | "\n", 29 | "def input_w(file, value):\n", 30 | " file.write('\\n' + value + '\\n')\n", 31 | "\n", 32 | "# 匹配中文\n", 33 | "\n", 34 | "\n", 35 | "def is_zh(line):\n", 36 | " xx = u\"([\\u4e00-\\u9fff]+)\"\n", 37 | " pattern = re.compile(xx)\n", 38 | " results = pattern.findall(line)\n", 39 | " return bool(results)\n", 40 | "# 匹配中英文\n", 41 | "\n", 42 | "\n", 43 | "def is_en_zh(line):\n", 44 | " xx = u\"([\\u4e00-\\u9fff]+)\"\n", 45 | " ch_pat = re.compile(xx)\n", 46 | " en_pat = re.compile('[a-zA-Z]+')\n", 47 | " ch_words = ch_pat.findall(line)\n", 48 | " en_words = en_pat.findall(line)\n", 49 | "\n", 50 | " return len(ch_words) and len(en_words)\n", 51 | "\n", 52 | "\n", 53 | "global py_is\n", 54 | "py_is = False\n", 55 | "\n", 56 | "\n", 57 | "def main():\n", 58 | " input_value = {\n", 59 | " 'h2': \"## \",\n", 60 | " 'start_tcode': \"``` py\\n\",\n", 61 | " 'end_code': '```\\n'\n", 62 | " }\n", 63 | "\n", 64 | " # 获得 文本文字\n", 65 | " try:\n", 66 | " Path = sys.argv[1]\n", 67 | " mkfileopen = open(Path)\n", 68 | " lines = mkfileopen.readlines()\n", 69 | " mkfileopen.close()\n", 70 | " except Exception as identifier:\n", 71 | " raise Exception('没有输入文件', identifier)\n", 72 | "\n", 73 | " # 不需要改变,直接写入,开头匹配\n", 74 | " res = [r\"``` py\", r\"更好的方法\", r\"#\", r\"```\", r'---', '']\n", 75 | " match_value_s = []\n", 76 | "\n", 77 | " for k, line in enumerate(lines):\n", 78 | " for re_value in res:\n", 79 | " if line.isspace():\n", 80 | " # \\n 换行 直接 插入\n", 81 | " # print('直接原文空格\\n',)\n", 82 | " match_value_s.append(line)\n", 83 | " break\n", 84 | "\n", 85 | " match_value = re.match(re_value, line.strip(), re.M | re.I)\n", 86 | "\n", 87 | " if match_value:\n", 88 | "\n", 89 | " # 代码开始—结束的区域固定\n", 90 | " # ``` py\n", 91 | " # ```\n", 92 | " # print('两个```py 代码', line)\n", 93 | " if py_is and re_value == r'``` py':\n", 94 | " match_value_s.append(input_value['end_code'] + line)\n", 95 | " py_is_fun('```')\n", 96 | " break\n", 97 | " elif re_value == r'``` py':\n", 98 | " py_is_fun(re_value)\n", 99 | " # print('本来开始代码', line)\n", 100 | " match_value_s.append(line)\n", 101 | " break\n", 102 | " elif re_value == r'```':\n", 103 | " # print('本来结束代码', line)\n", 104 | " match_value_s.append(line)\n", 105 | " py_is_fun('```')\n", 106 | " break\n", 107 | " elif py_is:\n", 108 | " # print('其他白名单前代码闭合', line)\n", 109 | " match_value_s.append(input_value['end_code'] + line)\n", 110 | " py_is_fun('```')\n", 111 | " break\n", 112 | " else:\n", 113 | " # print('原文白名单', line)\n", 114 | " match_value_s.append(line)\n", 115 | " break\n", 116 | "\n", 117 | " else:\n", 118 | "\n", 119 | " # 有中文有英文,不做处理\n", 120 | " # 多个中文片段\n", 121 | " if is_en_zh(line) is not 0 or is_zh(line) > 1:\n", 122 | " if py_is:\n", 123 | " match_value_s.append(input_value['end_code'] + line)\n", 124 | " # print('end', line)\n", 125 | " py_is_fun('```')\n", 126 | "\n", 127 | " else:\n", 128 | " # print('原本中文或英文不用加', line)\n", 129 | " match_value_s.append(line)\n", 130 | "\n", 131 | " # 单个中文片段,加 h2\n", 132 | " elif is_zh(line) and is_zh(line) <= 1:\n", 133 | " if py_is:\n", 134 | " match_value_s.append(\n", 135 | " input_value['end_code'] + input_value['h2'] + line)\n", 136 | " # print('加h2+end', line)\n", 137 | " py_is_fun('```')\n", 138 | "\n", 139 | " else:\n", 140 | " # print('加h2', line)\n", 141 | " match_value_s.append(input_value['h2'] + line)\n", 142 | " # 默认\n", 143 | " elif py_is is False:\n", 144 | "\n", 145 | " match_value_s.append(input_value['start_tcode'] + line)\n", 146 | " # print('start', str(k), repr(line))\n", 147 | " py_is_fun('``` py')\n", 148 | "\n", 149 | " else:\n", 150 | " # print('默认原文', line)\n", 151 | " match_value_s.append(line)\n", 152 | "\n", 153 | " if py_is is True:\n", 154 | " match_value_s.append('\\n' + input_value['end_code'])\n", 155 | "\n", 156 | " try:\n", 157 | " if len(sys.argv) > 2:\n", 158 | " write_file = sys.argv[2]\n", 159 | " else:\n", 160 | " write_file = Path\n", 161 | "\n", 162 | " if write_file.find('md') <= 0:\n", 163 | " write_file = write_file + '.md'\n", 164 | "\n", 165 | " file = open(write_file, 'w+')\n", 166 | " for i in match_value_s:\n", 167 | " file.write(i)\n", 168 | " file.close()\n", 169 | "\n", 170 | " output = \"< {} >file is create markdown from < {} >\".format(write_file, Path)\n", 171 | " cprint(output, 'green')\n", 172 | " \n", 173 | " except Exception as identifier:\n", 174 | " raise Exception(write_file, 'error', identifier)\n", 175 | "\n", 176 | "\n", 177 | "if __name__ == '__main__':\n", 178 | " main()\n" 179 | ] 180 | } 181 | ], 182 | "metadata": { 183 | "kernelspec": { 184 | "display_name": "Python 3", 185 | "language": "python", 186 | "name": "python3" 187 | }, 188 | "language_info": { 189 | "codemirror_mode": { 190 | "name": "ipython", 191 | "version": 3 192 | }, 193 | "file_extension": ".py", 194 | "mimetype": "text/x-python", 195 | "name": "python", 196 | "nbconvert_exporter": "python", 197 | "pygments_lexer": "ipython3", 198 | "version": "3.6.0" 199 | } 200 | }, 201 | "nbformat": 4, 202 | "nbformat_minor": 2 203 | } 204 | -------------------------------------------------------------------------------- /main/.ipynb_checkpoints/doc2md-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "collapsed": true 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "from __future__ import print_function\n", 12 | "from termcolor import cprint\n", 13 | "import re\n", 14 | "import sys\n", 15 | "import os\n", 16 | "\n", 17 | "# 全局 代码区域定义\n", 18 | "\n", 19 | "\n", 20 | "def py_is_fun(vv):\n", 21 | " global py_is\n", 22 | " if vv == '``` py':\n", 23 | " py_is = True\n", 24 | "\n", 25 | " elif vv == '```':\n", 26 | " py_is = False\n", 27 | "\n", 28 | "\n", 29 | "def input_w(file, value):\n", 30 | " file.write('\\n' + value + '\\n')\n", 31 | "\n", 32 | "# 匹配中文\n", 33 | "\n", 34 | "\n", 35 | "def is_zh(line):\n", 36 | " xx = u\"([\\u4e00-\\u9fff]+)\"\n", 37 | " pattern = re.compile(xx)\n", 38 | " results = pattern.findall(line)\n", 39 | " return bool(results)\n", 40 | "# 匹配中英文\n", 41 | "\n", 42 | "\n", 43 | "def is_en_zh(line):\n", 44 | " xx = u\"([\\u4e00-\\u9fff]+)\"\n", 45 | " ch_pat = re.compile(xx)\n", 46 | " en_pat = re.compile('[a-zA-Z]+')\n", 47 | " ch_words = ch_pat.findall(line)\n", 48 | " en_words = en_pat.findall(line)\n", 49 | "\n", 50 | " return len(ch_words) and len(en_words)\n", 51 | "\n", 52 | "\n", 53 | "global py_is\n", 54 | "py_is = False\n", 55 | "\n", 56 | "\n", 57 | "def main():\n", 58 | " input_value = {\n", 59 | " 'h2': \"## \",\n", 60 | " 'start_tcode': \"``` py\\n\",\n", 61 | " 'end_code': '```\\n'\n", 62 | " }\n", 63 | "\n", 64 | " # 获得 文本文字\n", 65 | " try:\n", 66 | " Path = sys.argv[1]\n", 67 | " mkfileopen = open(Path)\n", 68 | " lines = mkfileopen.readlines()\n", 69 | " mkfileopen.close()\n", 70 | " except Exception as identifier:\n", 71 | " raise Exception('没有输入文件', identifier)\n", 72 | "\n", 73 | " # 不需要改变,直接写入,开头匹配\n", 74 | " res = [r\"``` py\", r\"更好的方法\", r\"#\", r\"```\", r'---', '']\n", 75 | " match_value_s = []\n", 76 | "\n", 77 | " for k, line in enumerate(lines):\n", 78 | " for re_value in res:\n", 79 | " if line.isspace():\n", 80 | " # \\n 换行 直接 插入\n", 81 | " # print('直接原文空格\\n',)\n", 82 | " match_value_s.append(line)\n", 83 | " break\n", 84 | "\n", 85 | " match_value = re.match(re_value, line.strip(), re.M | re.I)\n", 86 | "\n", 87 | " if match_value:\n", 88 | "\n", 89 | " # 代码开始—结束的区域固定\n", 90 | " # ``` py\n", 91 | " # ```\n", 92 | " # print('两个```py 代码', line)\n", 93 | " if py_is and re_value == r'``` py':\n", 94 | " match_value_s.append(input_value['end_code'] + line)\n", 95 | " py_is_fun('```')\n", 96 | " break\n", 97 | " elif re_value == r'``` py':\n", 98 | " py_is_fun(re_value)\n", 99 | " # print('本来开始代码', line)\n", 100 | " match_value_s.append(line)\n", 101 | " break\n", 102 | " elif re_value == r'```':\n", 103 | " # print('本来结束代码', line)\n", 104 | " match_value_s.append(line)\n", 105 | " py_is_fun('```')\n", 106 | " break\n", 107 | " elif py_is:\n", 108 | " # print('其他白名单前代码闭合', line)\n", 109 | " match_value_s.append(input_value['end_code'] + line)\n", 110 | " py_is_fun('```')\n", 111 | " break\n", 112 | " else:\n", 113 | " # print('原文白名单', line)\n", 114 | " match_value_s.append(line)\n", 115 | " break\n", 116 | "\n", 117 | " else:\n", 118 | "\n", 119 | " # 有中文有英文,不做处理\n", 120 | " # 多个中文片段\n", 121 | " if is_en_zh(line) is not 0 or is_zh(line) > 1:\n", 122 | " if py_is:\n", 123 | " match_value_s.append(input_value['end_code'] + line)\n", 124 | " # print('end', line)\n", 125 | " py_is_fun('```')\n", 126 | "\n", 127 | " else:\n", 128 | " # print('原本中文或英文不用加', line)\n", 129 | " match_value_s.append(line)\n", 130 | "\n", 131 | " # 单个中文片段,加 h2\n", 132 | " elif is_zh(line) and is_zh(line) <= 1:\n", 133 | " if py_is:\n", 134 | " match_value_s.append(\n", 135 | " input_value['end_code'] + input_value['h2'] + line)\n", 136 | " # print('加h2+end', line)\n", 137 | " py_is_fun('```')\n", 138 | "\n", 139 | " else:\n", 140 | " # print('加h2', line)\n", 141 | " match_value_s.append(input_value['h2'] + line)\n", 142 | " # 默认\n", 143 | " elif py_is is False:\n", 144 | "\n", 145 | " match_value_s.append(input_value['start_tcode'] + line)\n", 146 | " # print('start', str(k), repr(line))\n", 147 | " py_is_fun('``` py')\n", 148 | "\n", 149 | " else:\n", 150 | " # print('默认原文', line)\n", 151 | " match_value_s.append(line)\n", 152 | "\n", 153 | " if py_is is True:\n", 154 | " match_value_s.append('\\n' + input_value['end_code'])\n", 155 | "\n", 156 | " try:\n", 157 | " if len(sys.argv) > 2:\n", 158 | " write_file = sys.argv[2]\n", 159 | " else:\n", 160 | " write_file = Path\n", 161 | "\n", 162 | " if write_file.find('md') <= 0:\n", 163 | " write_file = write_file + '.md'\n", 164 | "\n", 165 | " file = open(write_file, 'w+')\n", 166 | " for i in match_value_s:\n", 167 | " file.write(i)\n", 168 | " file.close()\n", 169 | "\n", 170 | " output = \"< {} >file is create markdown from < {} >\".format(write_file, Path)\n", 171 | " cprint(output, 'green')\n", 172 | " \n", 173 | " except Exception as identifier:\n", 174 | " raise Exception(write_file, 'error', identifier)\n", 175 | "\n", 176 | "\n", 177 | "if __name__ == '__main__':\n", 178 | " main()\n" 179 | ] 180 | } 181 | ], 182 | "metadata": { 183 | "kernelspec": { 184 | "display_name": "Python 3", 185 | "language": "python", 186 | "name": "python3" 187 | }, 188 | "language_info": { 189 | "codemirror_mode": { 190 | "name": "ipython", 191 | "version": 3 192 | }, 193 | "file_extension": ".py", 194 | "mimetype": "text/x-python", 195 | "name": "python", 196 | "nbconvert_exporter": "python", 197 | "pygments_lexer": "ipython3", 198 | "version": "3.6.0" 199 | } 200 | }, 201 | "nbformat": 4, 202 | "nbformat_minor": 2 203 | } 204 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python", 9 | "type": "python", 10 | "request": "launch", 11 | "stopOnEntry": true, 12 | "pythonPath": "${config:python.pythonPath}", 13 | "program": "${file}", 14 | "cwd": "${workspaceRoot}", 15 | "args": [ 16 | "1" 17 | ], 18 | "env": {}, 19 | "envFile": "${workspaceRoot}/.env", 20 | "debugOptions": [ 21 | "WaitOnAbnormalExit", 22 | "WaitOnNormalExit", 23 | "RedirectOutput" 24 | ] 25 | }, 26 | { 27 | "name": "PySpark", 28 | "type": "python", 29 | "request": "launch", 30 | "stopOnEntry": true, 31 | "osx": { 32 | "pythonPath": "${env:SPARK_HOME}/bin/spark-submit" 33 | }, 34 | "windows": { 35 | "pythonPath": "${env:SPARK_HOME}/bin/spark-submit.cmd" 36 | }, 37 | "linux": { 38 | "pythonPath": "${env:SPARK_HOME}/bin/spark-submit" 39 | }, 40 | "program": "${file}", 41 | "cwd": "${workspaceRoot}", 42 | "env": {}, 43 | "envFile": "${workspaceRoot}/.env", 44 | "debugOptions": [ 45 | "WaitOnAbnormalExit", 46 | "WaitOnNormalExit", 47 | "RedirectOutput" 48 | ] 49 | }, 50 | { 51 | "name": "Python Module", 52 | "type": "python", 53 | "request": "launch", 54 | "stopOnEntry": true, 55 | "pythonPath": "${config:python.pythonPath}", 56 | "module": "module.name", 57 | "cwd": "${workspaceRoot}", 58 | "env": {}, 59 | "envFile": "${workspaceRoot}/.env", 60 | "debugOptions": [ 61 | "WaitOnAbnormalExit", 62 | "WaitOnNormalExit", 63 | "RedirectOutput" 64 | ] 65 | }, 66 | { 67 | "name": "Integrated Terminal/Console", 68 | "type": "python", 69 | "request": "launch", 70 | "stopOnEntry": true, 71 | "pythonPath": "${config:python.pythonPath}", 72 | "program": "${file}", 73 | "cwd": "", 74 | "console": "integratedTerminal", 75 | "env": {}, 76 | "envFile": "${workspaceRoot}/.env", 77 | "debugOptions": [ 78 | "WaitOnAbnormalExit", 79 | "WaitOnNormalExit" 80 | ] 81 | }, 82 | { 83 | "name": "External Terminal/Console", 84 | "type": "python", 85 | "request": "launch", 86 | "stopOnEntry": true, 87 | "pythonPath": "${config:python.pythonPath}", 88 | "program": "${file}", 89 | "cwd": "", 90 | "console": "externalTerminal", 91 | "env": {}, 92 | "envFile": "${workspaceRoot}/.env", 93 | "debugOptions": [ 94 | "WaitOnAbnormalExit", 95 | "WaitOnNormalExit" 96 | ] 97 | }, 98 | { 99 | "name": "Django", 100 | "type": "python", 101 | "request": "launch", 102 | "stopOnEntry": true, 103 | "pythonPath": "${config:python.pythonPath}", 104 | "program": "${workspaceRoot}/manage.py", 105 | "cwd": "${workspaceRoot}", 106 | "args": [ 107 | "runserver", 108 | "--noreload", 109 | "--nothreading" 110 | ], 111 | "env": {}, 112 | "envFile": "${workspaceRoot}/.env", 113 | "debugOptions": [ 114 | "WaitOnAbnormalExit", 115 | "WaitOnNormalExit", 116 | "RedirectOutput", 117 | "DjangoDebugging" 118 | ] 119 | }, 120 | { 121 | "name": "Flask", 122 | "type": "python", 123 | "request": "launch", 124 | "stopOnEntry": false, 125 | "pythonPath": "${config:python.pythonPath}", 126 | "program": "fully qualified path fo 'flask' executable. Generally located along with python interpreter", 127 | "cwd": "${workspaceRoot}", 128 | "env": { 129 | "FLASK_APP": "${workspaceRoot}/quickstart/app.py" 130 | }, 131 | "args": [ 132 | "run", 133 | "--no-debugger", 134 | "--no-reload" 135 | ], 136 | "envFile": "${workspaceRoot}/.env", 137 | "debugOptions": [ 138 | "WaitOnAbnormalExit", 139 | "WaitOnNormalExit", 140 | "RedirectOutput" 141 | ] 142 | }, 143 | { 144 | "name": "Flask (old)", 145 | "type": "python", 146 | "request": "launch", 147 | "stopOnEntry": false, 148 | "pythonPath": "${config:python.pythonPath}", 149 | "program": "${workspaceRoot}/run.py", 150 | "cwd": "${workspaceRoot}", 151 | "args": [], 152 | "env": {}, 153 | "envFile": "${workspaceRoot}/.env", 154 | "debugOptions": [ 155 | "WaitOnAbnormalExit", 156 | "WaitOnNormalExit", 157 | "RedirectOutput" 158 | ] 159 | }, 160 | { 161 | "name": "Pyramid", 162 | "type": "python", 163 | "request": "launch", 164 | "stopOnEntry": true, 165 | "pythonPath": "${config:python.pythonPath}", 166 | "cwd": "${workspaceRoot}", 167 | "env": {}, 168 | "envFile": "${workspaceRoot}/.env", 169 | "args": [ 170 | "${workspaceRoot}/development.ini" 171 | ], 172 | "debugOptions": [ 173 | "WaitOnAbnormalExit", 174 | "WaitOnNormalExit", 175 | "RedirectOutput", 176 | "Pyramid" 177 | ] 178 | }, 179 | { 180 | "name": "Watson", 181 | "type": "python", 182 | "request": "launch", 183 | "stopOnEntry": true, 184 | "pythonPath": "${config:python.pythonPath}", 185 | "program": "${workspaceRoot}/console.py", 186 | "cwd": "${workspaceRoot}", 187 | "args": [ 188 | "dev", 189 | "runserver", 190 | "--noreload=True" 191 | ], 192 | "env": {}, 193 | "envFile": "${workspaceRoot}/.env", 194 | "debugOptions": [ 195 | "WaitOnAbnormalExit", 196 | "WaitOnNormalExit", 197 | "RedirectOutput" 198 | ] 199 | }, 200 | { 201 | "name": "Attach (Remote Debug)", 202 | "type": "python", 203 | "request": "attach", 204 | "localRoot": "${workspaceRoot}", 205 | "remoteRoot": "${workspaceRoot}", 206 | "port": 3000, 207 | "secret": "my_secret", 208 | "host": "localhost" 209 | } 210 | ] 211 | } -------------------------------------------------------------------------------- /让你的Python优雅.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: 让你的Python优雅 3 | thumbnail: 4 | 'http://tse2.mm.bing.net/th?id=OIP.HMoLaA0mOSlTzJRGppa0ZQEgEs&pid=15.1' 5 | date: 2017-09-16 09:28:28 6 | tags: [python, ] 7 | banner: 8 | --- 9 | 10 | 参考译文来自:www.lightxue.com/transforming-code-into-beautiful-idiomatic-python 11 | 12 | 在Python社区文化的浇灌下,演化出了一种独特的代码风格,去指导如何正确地使用Python,这就是常说的pythonic。 13 | 14 | Raymond Hettinger是Python核心开发者,本文提到的许多特性都是他开发的。同时他也是Python社区热忱的布道师,不遗余力地传授pythoni 15 | c之道。这篇文章是网友Jeff Paine整理的他在2013年美国的PyCon的演讲的笔记。 16 | 17 | --- 18 | 19 | 可下载 jupyter 20 | 点击下载 21 | 22 | 以下正文 23 | 24 | --- 25 | 26 | ## 遍历一个范围内的数字 27 | 28 | ``` py 29 | for i in [0, 1, 2, 3, 4, 5]: 30 | print i ** 2 31 | 32 | for i in range(6): 33 | print i ** 2 34 | ``` 35 | 36 | 更好的方法 37 | 38 | ``` py 39 | for i in xrange(6): 40 | print i ** 2 41 | ``` 42 | 43 | xrange会返回一个迭代器,用来一次 44 | 遍历一个范围。这种方式会比range更省内存。xrange在Python 3中已经改名为range。 45 | 46 | ## 遍历一个集合 47 | 48 | ``` py 49 | colors = ['red', 'green', 'blue', 'yellow'] 50 | 51 | for i in range(len(colors)): 52 | print colors[i] 53 | ``` 54 | 55 | 更好的方法 56 | 57 | ``` py 58 | for color in colors: 59 | print color 60 | ``` 61 | 62 | ## 反向遍历 63 | 64 | ``` py 65 | colors = ['red', 'green', 'blue', 'yellow'] 66 | 67 | for i in range(len(colors)-1, -1, -1): 68 | print colors[i] 69 | ``` 70 | 71 | 更好的方法 72 | 73 | ``` py 74 | for color in reversed(colors): 75 | print color 76 | ``` 77 | 78 | 79 | 80 | ## 遍历一个集合及其下标 81 | 82 | ``` py 83 | colors = ['red', 'green', 'blue', 'yellow'] 84 | 85 | for i in range(len(colors)): 86 | print i, '--->', colors[i] 87 | ``` 88 | 89 | 更好的方法 90 | 91 | ``` py 92 | for i, color in enumerate(colors): 93 | print i, '--->', color 94 | ``` 95 | 96 | 这种写法效率高,优雅,而且帮你省去亲自创建和自增下标。 97 | 98 | 当你发现你在操作集合的下标时,你很有可能在做错事。 99 | 100 | 101 | ## 遍历两个集合 102 | 103 | names = ['raymond', 'rachel', 'matthew'] 104 | colors = ['red', 'green', 'blue', 'yellow'] 105 | 106 | n = min(len(names), len(colors)) 107 | for i in range(n): 108 | print names[i], '--->', colors[i] 109 | 110 | for name, color in zip(names, colors): 111 | print name, '--->', color 112 | 113 | 更好的方法 114 | 115 | for name, color in izip(names, colors): 116 | print name, '--->', color 117 | 118 | zip在内存中生成一个新的列表,需要更多的内存。izip比zip效率更高。 119 | 120 | 注意:在Python 3中,izip改名为zip,并替换了原来的zip成为内置函数。 121 | 122 | 有序地遍历 123 | 124 | colors = ['red', 'green', 'blue', 'yellow'] 125 | 126 | # 正序 127 | for color in sorted(colors): 128 | print colors 129 | 130 | # 倒序 131 | for color in sorted(colors, reverse=True): 132 | print colors 133 | 134 | 自定义排序顺序 135 | 136 | colors = ['red', 'green', 'blue', 'yellow'] 137 | 138 | def compare_length(c1, c2): 139 | if len(c1) < len(c2): return -1 140 | if len(c1) > len(c2): return 1 141 | return 0 142 | 143 | print sorted(colors, cmp=compare_length) 144 | 145 | 更好的方法 146 | 147 | print sorted(colors, key=len) 148 | 149 | 第一种方法效率低而且写起来很不爽。另外,Python 3已经不支持比较函数了。 150 | 151 | 调用一个函数直到遇到标记值 152 | 153 | blocks = [] 154 | while True: 155 | block = f.read(32) 156 | if block == '': 157 | break 158 | blocks.append(block) 159 | 160 | 更好的方法 161 | 162 | blocks = [] 163 | for block in iter(partial(f.read, 32), ''): 164 | blocks.append(block) 165 | 166 | iter接受两个参数。第一个是你反复调用的函数,第二个是标记值。 167 | 168 | 译注:这个例子里不太能看出来方法二的优势,甚至觉得partial让代码可读性更差了。方法二的优势在于iter的返回值是个迭代器,迭代器能用在各种地方,set,s 169 | orted,min,max,heapq,sum…… 170 | 171 | 在循环内识别多个退出点 172 | 173 | def find(seq, target): 174 | found = False 175 | for i, value in enumerate(seq): 176 | if value == target: 177 | found = True 178 | break 179 | if not found: 180 | return -1 181 | return i 182 | 183 | 更好的方法 184 | 185 | def find(seq, target): 186 | for i, value in enumerate(seq): 187 | if value == target: 188 | break 189 | else: 190 | return -1 191 | return i 192 | 193 | for执行完所有的循环后就会执行else。 194 | 195 | 译注:刚了解for-else语法时会困惑,什么情况下会执行到else里。有两种方法去理解else。传统的方法是把for看作if,当for后面的条件为False时 196 | 执行else。其实条件为False时,就是for循环没被break出去,把所有循环都跑完的时候。所以另一种方法就是把else记成nobreak,当for没有被b 197 | reak,那么循环结束时会进入到else。 198 | 199 | 遍历字典的key 200 | 201 | d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'} 202 | 203 | for k in d: 204 | print k 205 | 206 | for k in d.keys(): 207 | if k.startswith('r'): 208 | del d[k] 209 | 210 | 什么时候应该使用第二种而不是第一种方法?当你需要修改字典的时候。 211 | 212 | 如果你在迭代一个东西的时候修改它,那就是在冒天下之大不韪,接下来发生什么都活该。 213 | 214 | d.keys()把字典里所有的key都复制到一个列表里。然后你就可以修改字典了。 215 | 216 | 注意:如果在Python 217 | 3里迭代一个字典你得显示地写:list(d.keys()),因为d.keys()返回的是一个“字典视图”(一个提供字典key的动态视图的迭代器)。详情请看文档。 218 | 219 | 遍历一个字典的key和value 220 | 221 | # 并不快,每次必须要重新哈希并做一次查找 222 | for k in d: 223 | print k, '--->', d[k] 224 | 225 | # 产生一个很大的列表 226 | for k, v in d.items(): 227 | print k, '--->', v 228 | 229 | 更好的方法 230 | 231 | for k, v in d.iteritems(): 232 | print k, '--->', v 233 | 234 | iteritems()更好是因为它返回了一个迭代器。 235 | 236 | 注意:Python 3已经没有iteritems()了,items()的行为和iteritems()很接近。详情请看文档。 237 | 238 | 用key-value对构建字典 239 | 240 | names = ['raymond', 'rachel', 'matthew'] 241 | colors = ['red', 'green', 'blue'] 242 | 243 | d = dict(izip(names, colors)) 244 | # {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'} 245 | 246 | Python 3: d = dict(zip(names, colors)) 247 | 248 | 用字典计数 249 | 250 | colors = ['red', 'green', 'red', 'blue', 'green', 'red'] 251 | 252 | # 简单,基本的计数方法。适合初学者起步时学习。 253 | d = {} 254 | for color in colors: 255 | if color not in d: 256 | d[color] = 0 257 | d[color] += 1 258 | 259 | # {'blue': 1, 'green': 2, 'red': 3} 260 | 261 | 更好的方法 262 | 263 | d = {} 264 | for color in colors: 265 | d[color] = d.get(color, 0) + 1 266 | 267 | # 稍微潮点的方法,但有些坑需要注意,适合熟练的老手。 268 | d = defaultdict(int) 269 | for color in colors: 270 | d[color] += 1 271 | 272 | 用字典分组 — 第I部分和第II部分 273 | 274 | names = ['raymond', 'rachel', 'matthew', 'roger', 275 | 'betty', 'melissa', 'judith', 'charlie'] 276 | 277 | # 在这个例子,我们按name的长度分组 278 | d = {} 279 | for name in names: 280 | key = len(name) 281 | if key not in d: 282 | d[key] = [] 283 | d[key].append(name) 284 | 285 | # {5: ['roger', 'betty'], 6: ['rachel', 'judith'], 7: ['raymond', 'matthew', 286 | 'melissa', 'charlie']} 287 | 288 | d = {} 289 | for name in names: 290 | key = len(name) 291 | d.setdefault(key, []).append(name) 292 | 293 | 更好的方法 294 | 295 | d = defaultdict(list) 296 | for name in names: 297 | key = len(name) 298 | d[key].append(name) 299 | 300 | 字典的popitem()是原子的吗? 301 | 302 | d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'} 303 | 304 | while d: 305 | key, value = d.popitem() 306 | print key, '-->', value 307 | 308 | popitem是原子的,所以多线程的时候没必要用锁包着它。 309 | 310 | 连接字典 311 | 312 | defaults = {'color': 'red', 'user': 'guest'} 313 | parser = argparse.ArgumentParser() 314 | parser.add_argument('-u', '--user') 315 | parser.add_argument('-c', '--color') 316 | namespace = parser.parse_args([]) 317 | command_line_args = {k: v for k, v in vars(namespace).items() if v} 318 | 319 | # 下面是通常的作法,默认使用第一个字典,接着用环境变量覆盖它,最后用命令行参数覆盖它。 320 | # 然而不幸的是,这种方法拷贝数据太疯狂。 321 | d = defaults.copy() 322 | d.update(os.environ) 323 | d.update(command_line_args) 324 | 325 | 更好的方法 326 | 327 | d = ChainMap(command_line_args, os.environ, defaults) 328 | 329 | ChainMap在Python 3中加入。高效而优雅。 330 | 331 | 提高可读性 332 | 333 | 位置参数和下标很漂亮 334 | 但关键字和名称更好 335 | 第一种方法对计算机来说很便利 336 | 第二种方法和人类思考方式一致 337 | 338 | 用关键字参数提高函数调用的可读性 339 | 340 | twitter_search('@obama', False, 20, True) 341 | 342 | 更好的方法 343 | 344 | twitter_search('@obama', retweets=False, numtweets=20, popular=True) 345 | 346 | 第二种方法稍微(微秒级)慢一点,但为了代码的可读性和开发时间,值得。 347 | 348 | 用namedtuple提高多个返回值的可读性 349 | 350 | # 老的testmod返回值 351 | doctest.testmod() 352 | # (0, 4) 353 | # 测试结果是好是坏?你看不出来,因为返回值不清晰。 354 | 355 | 更好的方法 356 | 357 | # 新的testmod返回值, 一个namedtuple 358 | doctest.testmod() 359 | # TestResults(failed=0, attempted=4) 360 | 361 | namedtuple是tuple的子类,所以仍适用正常的元组操作,但它更友好。 362 | 363 | 创建一个nametuple 364 | 365 | TestResults = namedTuple('TestResults', ['failed', 'attempted']) 366 | 367 | unpack序列 368 | 369 | p = 'Raymond', 'Hettinger', 0x30, 'python@example.com' 370 | 371 | # 其它语言的常用方法/习惯 372 | fname = p[0] 373 | lname = p[1] 374 | age = p[2] 375 | email = p[3] 376 | 377 | 更好的方法 378 | 379 | fname, lname, age, email = p 380 | 381 | 第二种方法用了unpack元组,更快,可读性更好。 382 | 383 | 更新多个变量的状态 384 | 385 | def fibonacci(n): 386 | x = 0 387 | y = 1 388 | for i in range(n): 389 | print x 390 | t = y 391 | y = x + y 392 | x = t 393 | 394 | 更好的方法 395 | 396 | def fibonacci(n): 397 | x, y = 0, 1 398 | for i in range(n): 399 | print x 400 | x, y = y, x + y 401 | 402 | 第一种方法的问题 403 | 404 | x和y是状态,状态应该在一次操作中更新,分几行的话状态会互相对不上,这经常是bug的源头。 405 | 操作有顺序要求 406 | 太底层太细节 407 | 408 | 第二种方法抽象层级更高,没有操作顺序出错的风险而且更效率更高。 409 | 410 | 同时状态更新 411 | 412 | tmp_x = x + dx * t 413 | tmp_y = y + dy * t 414 | tmp_dx = influence(m, x, y, dx, dy, partial='x') 415 | tmp_dy = influence(m, x, y, dx, dy, partial='y') 416 | x = tmp_x 417 | y = tmp_y 418 | dx = tmp_dx 419 | dy = tmp_dy 420 | 421 | 更好的方法 422 | 423 | x, y, dx, dy = (x + dx * t, 424 | y + dy * t, 425 | influence(m, x, y, dx, dy, partial='x'), 426 | influence(m, x, y, dx, dy, partial='y')) 427 | 428 | 效率 429 | 430 | 优化的基本原则 431 | 除非必要,别无故移动数据 432 | 稍微注意一下用线性的操作取代O(n**2)的操作 433 | 434 | 总的来说,不要无故移动数据 435 | 436 | 连接字符串 437 | 438 | names = ['raymond', 'rachel', 'matthew', 'roger', 439 | 'betty', 'melissa', 'judith', 'charlie'] 440 | 441 | s = names[0] 442 | for name in names[1:]: 443 | s += ', ' + name 444 | print s 445 | 446 | 更好的方法 447 | 448 | print ', '.join(names) 449 | 450 | 更新序列 451 | 452 | names = ['raymond', 'rachel', 'matthew', 'roger', 453 | 'betty', 'melissa', 'judith', 'charlie'] 454 | 455 | del names[0] 456 | # 下面的代码标志着你用错了数据结构 457 | names.pop(0) 458 | names.insert(0, 'mark') 459 | 460 | 更好的方法 461 | 462 | names = deque(['raymond', 'rachel', 'matthew', 'roger', 463 | 'betty', 'melissa', 'judith', 'charlie']) 464 | 465 | # 用deque更有效率 466 | del names[0] 467 | names.popleft() 468 | names.appendleft('mark') 469 | 470 | 装饰器和上下文管理 471 | 472 | 用于把业务和管理的逻辑分开 473 | 分解代码和提高代码重用性的干净优雅的好工具 474 | 起个好名字很关键 475 | 记住蜘蛛侠的格言:能力越大,责任越大 476 | 477 | 使用装饰器分离出管理逻辑 478 | 479 | # 混着业务和管理逻辑,无法重用 480 | def web_lookup(url, saved={}): 481 | if url in saved: 482 | return saved[url] 483 | page = urllib.urlopen(url).read() 484 | saved[url] = page 485 | return page 486 | 487 | 更好的方法 488 | 489 | @cache 490 | def web_lookup(url): 491 | return urllib.urlopen(url).read() 492 | 493 | 注意:Python 3.2开始加入了functools.lru_cache解决这个问题。 494 | 495 | 分离临时上下文 496 | 497 | # 保存旧的,创建新的 498 | old_context = getcontext().copy() 499 | getcontext().prec = 50 500 | print Decimal(355) / Decimal(113) 501 | setcontext(old_context) 502 | 503 | 更好的方法 504 | 505 | with localcontext(Context(prec=50)): 506 | print Decimal(355) / Decimal(113) 507 | 508 | 译注:示例代码在使用标准库decimal,这个库已经实现好了localcontext。 509 | 510 | 如何打开关闭文件 511 | 512 | f = open('data.txt') 513 | try: 514 | data = f.read() 515 | finally: 516 | f.close() 517 | 518 | 更好的方法 519 | 520 | with open('data.txt') as f: 521 | data = f.read() 522 | 523 | 如何使用锁 524 | 525 | # 创建锁 526 | lock = threading.Lock() 527 | 528 | # 使用锁的老方法 529 | lock.acquire() 530 | try: 531 | print 'Critical section 1' 532 | print 'Critical section 2' 533 | finally: 534 | lock.release() 535 | 536 | 更好的方法 537 | 538 | # 使用锁的新方法 539 | with lock: 540 | print 'Critical section 1' 541 | print 'Critical section 2' 542 | 543 | 分离出临时的上下文 544 | 545 | try: 546 | os.remove('somefile.tmp') 547 | except OSError: 548 | pass 549 | 550 | 更好的方法 551 | 552 | with ignored(OSError): 553 | os.remove('somefile.tmp') 554 | 555 | ignored是Python 3.4加入的, 文档。 556 | 557 | 注意:ignored 实际上在标准库叫suppress(译注:contextlib.supress). 558 | 559 | 试试创建你自己的ignored上下文管理器。 560 | 561 | @contextmanager 562 | def ignored(*exceptions): 563 | try: 564 | yield 565 | except exceptions: 566 | pass 567 | 568 | 把它放在你的工具目录,你也可以忽略异常 569 | 570 | 译注:contextmanager在标准库contextlib中,通过装饰生成器函数,省去用__enter__和__exit__写上下文管理器。详情请看文档。 571 | 572 | 分离临时上下文 573 | 574 | # 临时把标准输出重定向到一个文件,然后再恢复正常 575 | with open('help.txt', 'w') as f: 576 | oldstdout = sys.stdout 577 | sys.stdout = f 578 | try: 579 | help(pow) 580 | finally: 581 | sys.stdout = oldstdout 582 | 583 | 更好的写法 584 | 585 | with open('help.txt', 'w') as f: 586 | with redirect_stdout(f): 587 | help(pow) 588 | 589 | redirect_stdout在Python 3.4加入(译注:contextlib.redirect_stdout), bug反馈。 590 | 591 | 实现你自己的redirect_stdout上下文管理器。 592 | 593 | @contextmanager 594 | def redirect_stdout(fileobj): 595 | oldstdout = sys.stdout 596 | sys.stdout = fileobj 597 | try: 598 | yield fieldobj 599 | finally: 600 | sys.stdout = oldstdout 601 | 602 | 简洁的单句表达 603 | 604 | 两个冲突的原则: 605 | 606 | 一行不要有太多逻辑 607 | 不要把单一的想法拆分成多个部分 608 | 609 | Raymond的原则: 610 | 611 | 一行代码的逻辑等价于一句自然语言 612 | 613 | 列表解析和生成器 614 | 615 | result = [] 616 | for i in range(10): 617 | s = i ** 2 618 | result.append(s) 619 | print sum(result) 620 | 621 | 更好的方法 622 | 623 | print sum(i**2 for i in xrange(10)) 624 | 625 | 第一种方法说的是你在做什么,第二种方法说的是你想要什么。 626 | -------------------------------------------------------------------------------- /main/.ipynb_checkpoints/markdown_md-checkpoint.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "metadata": { 7 | "ExecuteTime": { 8 | "end_time": "2017-09-26T12:40:00.199024Z", 9 | "start_time": "2017-09-26T12:40:00.192767Z" 10 | }, 11 | "collapsed": true 12 | }, 13 | "outputs": [], 14 | "source": [ 15 | "import re\n", 16 | "import os" 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "### ---" 24 | ] 25 | }, 26 | { 27 | "cell_type": "code", 28 | "execution_count": 3, 29 | "metadata": { 30 | "ExecuteTime": { 31 | "end_time": "2017-09-26T12:40:00.205306Z", 32 | "start_time": "2017-09-26T12:40:00.201426Z" 33 | }, 34 | "collapsed": false 35 | }, 36 | "outputs": [], 37 | "source": [ 38 | "global py_is\n", 39 | "py_is = False\n", 40 | "\n", 41 | "# 全局 代码区域定义" 42 | ] 43 | }, 44 | { 45 | "cell_type": "code", 46 | "execution_count": 4, 47 | "metadata": { 48 | "ExecuteTime": { 49 | "end_time": "2017-09-26T12:40:00.213939Z", 50 | "start_time": "2017-09-26T12:40:00.208497Z" 51 | }, 52 | "collapsed": false 53 | }, 54 | "outputs": [], 55 | "source": [ 56 | "def py_is_fun( vv ):\n", 57 | " global py_is\n", 58 | " if vv == '``` py':\n", 59 | " py_is = True\n", 60 | " \n", 61 | " elif vv == '```': \n", 62 | " py_is = False\n", 63 | " " 64 | ] 65 | }, 66 | { 67 | "cell_type": "markdown", 68 | "metadata": { 69 | "ExecuteTime": { 70 | "end_time": "2017-09-16T16:43:44.410005Z", 71 | "start_time": "2017-09-16T16:43:44.404243Z" 72 | } 73 | }, 74 | "source": [ 75 | "---" 76 | ] 77 | }, 78 | { 79 | "cell_type": "code", 80 | "execution_count": 5, 81 | "metadata": { 82 | "ExecuteTime": { 83 | "end_time": "2017-09-26T12:40:00.219491Z", 84 | "start_time": "2017-09-26T12:40:00.216123Z" 85 | }, 86 | "collapsed": false 87 | }, 88 | "outputs": [], 89 | "source": [ 90 | "def input_w( file, value ):\n", 91 | " file.write('\\n'+value+'\\n')" 92 | ] 93 | }, 94 | { 95 | "cell_type": "code", 96 | "execution_count": 6, 97 | "metadata": { 98 | "ExecuteTime": { 99 | "end_time": "2017-09-26T12:40:00.225803Z", 100 | "start_time": "2017-09-26T12:40:00.221716Z" 101 | }, 102 | "collapsed": true 103 | }, 104 | "outputs": [], 105 | "source": [ 106 | "input_value = {\n", 107 | " 'h2': \"## \",\n", 108 | " 'start_tcode': \"``` py\\n\",\n", 109 | " 'end_code': '```\\n'\n", 110 | "}" 111 | ] 112 | }, 113 | { 114 | "cell_type": "code", 115 | "execution_count": 7, 116 | "metadata": { 117 | "ExecuteTime": { 118 | "end_time": "2017-09-26T12:40:00.232713Z", 119 | "start_time": "2017-09-26T12:40:00.227674Z" 120 | }, 121 | "collapsed": true 122 | }, 123 | "outputs": [], 124 | "source": [ 125 | "Path = \"../让你的Python优雅.md\"\n", 126 | "mkfileopen = open(Path)\n", 127 | "lines = mkfileopen.readlines()\n", 128 | "mkfileopen.close()\n", 129 | "# 获得 文本文字" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": 8, 135 | "metadata": { 136 | "ExecuteTime": { 137 | "end_time": "2017-09-26T12:40:00.243264Z", 138 | "start_time": "2017-09-26T12:40:00.234830Z" 139 | }, 140 | "collapsed": true 141 | }, 142 | "outputs": [], 143 | "source": [ 144 | "# 不需要改变,直接写入,开头匹配\n", 145 | "res = [r\"``` py\", r\"更好的方法\", r\"#\", r\"```\", r'---','']\n", 146 | "# 匹配中文\n", 147 | "def is_zh(line):\n", 148 | " xx = u\"([\\u4e00-\\u9fff]+)\" \n", 149 | " pattern = re.compile(xx) \n", 150 | " results = pattern.findall(line)\n", 151 | " return bool(results)\n", 152 | "# 匹配中英文\n", 153 | "def is_en_zh(line):\n", 154 | " xx = u\"([\\w\\W]+[\\u4e00-\\u9fff]+)\" \n", 155 | " pattern = re.compile(xx) \n", 156 | " results = pattern.findall(line)\n", 157 | " return len(results)\n" 158 | ] 159 | }, 160 | { 161 | "cell_type": "code", 162 | "execution_count": 9, 163 | "metadata": { 164 | "ExecuteTime": { 165 | "end_time": "2017-09-26T12:40:00.502998Z", 166 | "start_time": "2017-09-26T12:40:00.244949Z" 167 | }, 168 | "collapsed": false, 169 | "scrolled": true 170 | }, 171 | "outputs": [ 172 | { 173 | "name": "stdout", 174 | "output_type": "stream", 175 | "text": [ 176 | "原文白名单 ---\n", 177 | "\n", 178 | "原本中文或英文不用加 title: 让你的Python优雅\n", 179 | "\n", 180 | "start 2 'thumbnail:\\n'\n", 181 | "默认原文 'http://tse2.mm.bing.net/th?id=OIP.HMoLaA0mOSlTzJRGppa0ZQEgEs&pid=15.1'\n", 182 | "\n", 183 | "默认原文 date: 2017-09-16 09:28:28\n", 184 | "\n", 185 | "默认原文 tags: [python, ]\n", 186 | "\n", 187 | "默认原文 banner:\n", 188 | "\n", 189 | "其他白名单前代码闭合 ---\n", 190 | "\n", 191 | "直接原文空格\n", 192 | "\n", 193 | "原本中文或英文不用加 参考译文来自:www.lightxue.com/transforming-code-into-beautiful-idiomatic-python\n", 194 | "\n", 195 | "直接原文空格\n", 196 | "\n", 197 | "原本中文或英文不用加 在Python社区文化的浇灌下,演化出了一种独特的代码风格,去指导如何正确地使用Python,这就是常说的pythonic。\n", 198 | "\n", 199 | "直接原文空格\n", 200 | "\n", 201 | "原本中文或英文不用加 Raymond Hettinger是Python核心开发者,本文提到的许多特性都是他开发的。同时他也是Python社区热忱的布道师,不遗余力地传授pythoni\n", 202 | "\n", 203 | "原本中文或英文不用加 c之道。这篇文章是网友Jeff Paine整理的他在2013年美国的PyCon的演讲的笔记。\n", 204 | "\n", 205 | "直接原文空格\n", 206 | "\n", 207 | "原文白名单 ---\n", 208 | "\n", 209 | "直接原文空格\n", 210 | "\n", 211 | "原本中文或英文不用加 可下载 jupyter\n", 212 | "\n", 213 | "原本中文或英文不用加 点击下载\n", 214 | "\n", 215 | "直接原文空格\n", 216 | "\n", 217 | "原本中文或英文不用加 以下正文\n", 218 | "\n", 219 | "直接原文空格\n", 220 | "\n", 221 | "原文白名单 ---\n", 222 | "\n", 223 | "直接原文空格\n", 224 | "\n", 225 | "原文白名单 ## 遍历一个范围内的数字\n", 226 | "\n", 227 | "直接原文空格\n", 228 | "\n", 229 | "本来开始代码 ``` py\n", 230 | "\n", 231 | "默认原文 for i in [0, 1, 2, 3, 4, 5]:\n", 232 | "\n", 233 | "默认原文 print i ** 2\n", 234 | "\n", 235 | "直接原文空格\n", 236 | "\n", 237 | "默认原文 for i in range(6):\n", 238 | "\n", 239 | "默认原文 print i ** 2\n", 240 | "\n", 241 | "本来结束代码 ```\n", 242 | "\n", 243 | "直接原文空格\n", 244 | "\n", 245 | "原文白名单 更好的方法\n", 246 | "\n", 247 | "直接原文空格\n", 248 | "\n", 249 | "本来开始代码 ``` py\n", 250 | "\n", 251 | "默认原文 for i in xrange(6):\n", 252 | "\n", 253 | "默认原文 print i ** 2\n", 254 | "\n", 255 | "本来结束代码 ```\n", 256 | "\n", 257 | "直接原文空格\n", 258 | "\n", 259 | "原本中文或英文不用加 xrange会返回一个迭代器,用来一次\n", 260 | "\n", 261 | "原本中文或英文不用加 遍历一个范围。这种方式会比range更省内存。xrange在Python 3中已经改名为range。\n", 262 | "\n", 263 | "直接原文空格\n", 264 | "\n", 265 | "原文白名单 ## 遍历一个集合\n", 266 | "\n", 267 | "直接原文空格\n", 268 | "\n", 269 | "本来开始代码 ``` py\n", 270 | "\n", 271 | "默认原文 colors = ['red', 'green', 'blue', 'yellow']\n", 272 | "\n", 273 | "直接原文空格\n", 274 | "\n", 275 | "默认原文 for i in range(len(colors)):\n", 276 | "\n", 277 | "默认原文 print colors[i]\n", 278 | "\n", 279 | "本来结束代码 ```\n", 280 | "\n", 281 | "直接原文空格\n", 282 | "\n", 283 | "原文白名单 更好的方法\n", 284 | "\n", 285 | "直接原文空格\n", 286 | "\n", 287 | "本来开始代码 ``` py\n", 288 | "\n", 289 | "默认原文 for color in colors:\n", 290 | "\n", 291 | "默认原文 print color\n", 292 | "\n", 293 | "本来结束代码 ```\n", 294 | "\n", 295 | "直接原文空格\n", 296 | "\n", 297 | "原文白名单 ## 反向遍历\n", 298 | "\n", 299 | "直接原文空格\n", 300 | "\n", 301 | "本来开始代码 ``` py\n", 302 | "\n", 303 | "默认原文 colors = ['red', 'green', 'blue', 'yellow']\n", 304 | "\n", 305 | "直接原文空格\n", 306 | "\n", 307 | "默认原文 for i in range(len(colors)-1, -1, -1):\n", 308 | "\n", 309 | "默认原文 print colors[i]\n", 310 | "\n", 311 | "本来结束代码 ```\n", 312 | "\n", 313 | "直接原文空格\n", 314 | "\n", 315 | "原文白名单 更好的方法\n", 316 | "\n", 317 | "直接原文空格\n", 318 | "\n", 319 | "本来开始代码 ``` py\n", 320 | "\n", 321 | "默认原文 for color in reversed(colors):\n", 322 | "\n", 323 | "默认原文 print color\n", 324 | "\n", 325 | "本来结束代码 ```\n", 326 | "\n", 327 | "直接原文空格\n", 328 | "\n", 329 | "原文白名单 \n", 330 | "\n", 331 | "直接原文空格\n", 332 | "\n", 333 | "原文白名单 ## 遍历一个集合及其下标\n", 334 | "\n", 335 | "直接原文空格\n", 336 | "\n", 337 | "本来开始代码 ``` py\n", 338 | "\n", 339 | "默认原文 colors = ['red', 'green', 'blue', 'yellow']\n", 340 | "\n", 341 | "直接原文空格\n", 342 | "\n", 343 | "默认原文 for i in range(len(colors)):\n", 344 | "\n", 345 | "默认原文 print i, '--->', colors[i]\n", 346 | "\n", 347 | "本来结束代码 ```\n", 348 | "\n", 349 | "直接原文空格\n", 350 | "\n", 351 | "原文白名单 更好的方法\n", 352 | "\n", 353 | "直接原文空格\n", 354 | "\n", 355 | "本来开始代码 ``` py\n", 356 | "\n", 357 | "默认原文 for i, color in enumerate(colors):\n", 358 | "\n", 359 | "默认原文 print i, '--->', color\n", 360 | "\n", 361 | "本来结束代码 ```\n", 362 | "\n", 363 | "直接原文空格\n", 364 | "\n", 365 | "原本中文或英文不用加 这种写法效率高,优雅,而且帮你省去亲自创建和自增下标。\n", 366 | "\n", 367 | "直接原文空格\n", 368 | "\n", 369 | "原本中文或英文不用加 当你发现你在操作集合的下标时,你很有可能在做错事。\n", 370 | "\n", 371 | "直接原文空格\n", 372 | "\n", 373 | "直接原文空格\n", 374 | "\n", 375 | "原文白名单 ## 遍历两个集合\n", 376 | "\n", 377 | "直接原文空格\n", 378 | "\n", 379 | "start 102 \"names = ['raymond', 'rachel', 'matthew']\\n\"\n", 380 | "默认原文 colors = ['red', 'green', 'blue', 'yellow']\n", 381 | "\n", 382 | "直接原文空格\n", 383 | "\n", 384 | "默认原文 n = min(len(names), len(colors))\n", 385 | "\n", 386 | "默认原文 for i in range(n):\n", 387 | "\n", 388 | "默认原文 print names[i], '--->', colors[i]\n", 389 | "\n", 390 | "直接原文空格\n", 391 | "\n", 392 | "默认原文 for name, color in zip(names, colors):\n", 393 | "\n", 394 | "默认原文 print name, '--->', color\n", 395 | "\n", 396 | "直接原文空格\n", 397 | "\n", 398 | "其他白名单前代码闭合 更好的方法\n", 399 | "\n", 400 | "直接原文空格\n", 401 | "\n", 402 | "start 114 'for name, color in izip(names, colors):\\n'\n", 403 | "默认原文 print name, '--->', color\n", 404 | "\n", 405 | "直接原文空格\n", 406 | "\n", 407 | "end zip在内存中生成一个新的列表,需要更多的内存。izip比zip效率更高。\n", 408 | "\n", 409 | "直接原文空格\n", 410 | "\n", 411 | "原本中文或英文不用加 注意:在Python 3中,izip改名为zip,并替换了原来的zip成为内置函数。\n", 412 | "\n", 413 | "直接原文空格\n", 414 | "\n", 415 | "原本中文或英文不用加 有序地遍历\n", 416 | "\n", 417 | "直接原文空格\n", 418 | "\n", 419 | "start 123 \"colors = ['red', 'green', 'blue', 'yellow']\\n\"\n", 420 | "直接原文空格\n", 421 | "\n", 422 | "其他白名单前代码闭合 # 正序\n", 423 | "\n", 424 | "start 126 'for color in sorted(colors):\\n'\n", 425 | "默认原文 print colors\n", 426 | "\n", 427 | "直接原文空格\n", 428 | "\n", 429 | "其他白名单前代码闭合 # 倒序\n", 430 | "\n", 431 | "start 130 'for color in sorted(colors, reverse=True):\\n'\n", 432 | "默认原文 print colors\n", 433 | "\n", 434 | "直接原文空格\n", 435 | "\n", 436 | "end 自定义排序顺序\n", 437 | "\n", 438 | "直接原文空格\n", 439 | "\n", 440 | "start 135 \"colors = ['red', 'green', 'blue', 'yellow']\\n\"\n", 441 | "直接原文空格\n", 442 | "\n", 443 | "默认原文 def compare_length(c1, c2):\n", 444 | "\n", 445 | "默认原文 if len(c1) < len(c2): return -1\n", 446 | "\n", 447 | "默认原文 if len(c1) > len(c2): return 1\n", 448 | "\n", 449 | "默认原文 return 0\n", 450 | "\n", 451 | "直接原文空格\n", 452 | "\n", 453 | "默认原文 print sorted(colors, cmp=compare_length)\n", 454 | "\n", 455 | "直接原文空格\n", 456 | "\n", 457 | "其他白名单前代码闭合 更好的方法\n", 458 | "\n", 459 | "直接原文空格\n", 460 | "\n", 461 | "start 146 'print sorted(colors, key=len)\\n'\n", 462 | "直接原文空格\n", 463 | "\n", 464 | "end 第一种方法效率低而且写起来很不爽。另外,Python 3已经不支持比较函数了。\n", 465 | "\n", 466 | "直接原文空格\n", 467 | "\n", 468 | "原本中文或英文不用加 调用一个函数直到遇到标记值\n", 469 | "\n", 470 | "直接原文空格\n", 471 | "\n", 472 | "start 152 'blocks = []\\n'\n", 473 | "默认原文 while True:\n", 474 | "\n", 475 | "默认原文 block = f.read(32)\n", 476 | "\n", 477 | "默认原文 if block == '':\n", 478 | "\n", 479 | "默认原文 break\n", 480 | "\n", 481 | "默认原文 blocks.append(block)\n", 482 | "\n", 483 | "直接原文空格\n", 484 | "\n", 485 | "其他白名单前代码闭合 更好的方法\n", 486 | "\n", 487 | "直接原文空格\n", 488 | "\n", 489 | "start 161 'blocks = []\\n'\n", 490 | "默认原文 for block in iter(partial(f.read, 32), ''):\n", 491 | "\n", 492 | "默认原文 blocks.append(block)\n", 493 | "\n", 494 | "直接原文空格\n", 495 | "\n", 496 | "end iter接受两个参数。第一个是你反复调用的函数,第二个是标记值。\n", 497 | "\n", 498 | "直接原文空格\n", 499 | "\n", 500 | "原本中文或英文不用加 译注:这个例子里不太能看出来方法二的优势,甚至觉得partial让代码可读性更差了。方法二的优势在于iter的返回值是个迭代器,迭代器能用在各种地方,set,s\n", 501 | "\n", 502 | "start 168 'orted,min,max,heapq,sum……\\n'\n", 503 | "直接原文空格\n", 504 | "\n", 505 | "end 在循环内识别多个退出点\n", 506 | "\n", 507 | "直接原文空格\n", 508 | "\n", 509 | "start 172 'def find(seq, target):\\n'\n", 510 | "默认原文 found = False\n", 511 | "\n", 512 | "默认原文 for i, value in enumerate(seq):\n", 513 | "\n", 514 | "默认原文 if value == target:\n", 515 | "\n", 516 | "默认原文 found = True\n", 517 | "\n", 518 | "默认原文 break\n", 519 | "\n", 520 | "默认原文 if not found:\n", 521 | "\n", 522 | "默认原文 return -1\n", 523 | "\n", 524 | "默认原文 return i\n", 525 | "\n", 526 | "直接原文空格\n", 527 | "\n", 528 | "其他白名单前代码闭合 更好的方法\n", 529 | "\n", 530 | "直接原文空格\n", 531 | "\n", 532 | "start 184 'def find(seq, target):\\n'\n", 533 | "默认原文 for i, value in enumerate(seq):\n", 534 | "\n", 535 | "默认原文 if value == target:\n", 536 | "\n", 537 | "默认原文 break\n", 538 | "\n", 539 | "默认原文 else:\n", 540 | "\n", 541 | "默认原文 return -1\n", 542 | "\n", 543 | "默认原文 return i\n", 544 | "\n", 545 | "直接原文空格\n", 546 | "\n", 547 | "end for执行完所有的循环后就会执行else。\n", 548 | "\n", 549 | "直接原文空格\n", 550 | "\n", 551 | "原本中文或英文不用加 译注:刚了解for-else语法时会困惑,什么情况下会执行到else里。有两种方法去理解else。传统的方法是把for看作if,当for后面的条件为False时\n", 552 | "\n", 553 | "原本中文或英文不用加 执行else。其实条件为False时,就是for循环没被break出去,把所有循环都跑完的时候。所以另一种方法就是把else记成nobreak,当for没有被b\n", 554 | "\n", 555 | "原本中文或英文不用加 reak,那么循环结束时会进入到else。\n", 556 | "\n", 557 | "直接原文空格\n", 558 | "\n", 559 | "原本中文或英文不用加 遍历字典的key\n", 560 | "\n", 561 | "直接原文空格\n", 562 | "\n", 563 | "start 200 \"d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}\\n\"\n", 564 | "直接原文空格\n", 565 | "\n", 566 | "默认原文 for k in d:\n", 567 | "\n", 568 | "默认原文 print k\n", 569 | "\n", 570 | "直接原文空格\n", 571 | "\n", 572 | "默认原文 for k in d.keys():\n", 573 | "\n", 574 | "默认原文 if k.startswith('r'):\n", 575 | "\n", 576 | "默认原文 del d[k]\n", 577 | "\n", 578 | "直接原文空格\n", 579 | "\n", 580 | "end 什么时候应该使用第二种而不是第一种方法?当你需要修改字典的时候。\n", 581 | "\n", 582 | "直接原文空格\n", 583 | "\n", 584 | "原本中文或英文不用加 如果你在迭代一个东西的时候修改它,那就是在冒天下之大不韪,接下来发生什么都活该。\n", 585 | "\n", 586 | "直接原文空格\n", 587 | "\n", 588 | "原本中文或英文不用加 d.keys()把字典里所有的key都复制到一个列表里。然后你就可以修改字典了。\n", 589 | "\n", 590 | "直接原文空格\n", 591 | "\n", 592 | "原本中文或英文不用加 注意:如果在Python\n", 593 | "\n", 594 | "原本中文或英文不用加 3里迭代一个字典你得显示地写:list(d.keys()),因为d.keys()返回的是一个“字典视图”(一个提供字典key的动态视图的迭代器)。详情请看文档。\n", 595 | "\n", 596 | "直接原文空格\n", 597 | "\n", 598 | "原本中文或英文不用加 遍历一个字典的key和value\n", 599 | "\n", 600 | "直接原文空格\n", 601 | "\n", 602 | "原文白名单 # 并不快,每次必须要重新哈希并做一次查找\n", 603 | "\n", 604 | "start 221 'for k in d:\\n'\n", 605 | "默认原文 print k, '--->', d[k]\n", 606 | "\n", 607 | "直接原文空格\n", 608 | "\n", 609 | "其他白名单前代码闭合 # 产生一个很大的列表\n", 610 | "\n", 611 | "start 225 'for k, v in d.items():\\n'\n", 612 | "默认原文 print k, '--->', v\n", 613 | "\n", 614 | "直接原文空格\n", 615 | "\n", 616 | "其他白名单前代码闭合 更好的方法\n", 617 | "\n", 618 | "直接原文空格\n", 619 | "\n", 620 | "start 230 'for k, v in d.iteritems():\\n'\n", 621 | "默认原文 print k, '--->', v\n", 622 | "\n", 623 | "直接原文空格\n", 624 | "\n", 625 | "end iteritems()更好是因为它返回了一个迭代器。\n", 626 | "\n", 627 | "直接原文空格\n", 628 | "\n", 629 | "原本中文或英文不用加 注意:Python 3已经没有iteritems()了,items()的行为和iteritems()很接近。详情请看文档。\n", 630 | "\n", 631 | "直接原文空格\n", 632 | "\n", 633 | "原本中文或英文不用加 用key-value对构建字典\n", 634 | "\n", 635 | "直接原文空格\n", 636 | "\n", 637 | "start 239 \"names = ['raymond', 'rachel', 'matthew']\\n\"\n", 638 | "默认原文 colors = ['red', 'green', 'blue']\n", 639 | "\n", 640 | "直接原文空格\n", 641 | "\n", 642 | "默认原文 d = dict(izip(names, colors))\n", 643 | "\n", 644 | "其他白名单前代码闭合 # {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}\n", 645 | "\n", 646 | "直接原文空格\n", 647 | "\n", 648 | "start 245 'Python 3: d = dict(zip(names, colors))\\n'\n", 649 | "直接原文空格\n", 650 | "\n", 651 | "end 用字典计数\n", 652 | "\n", 653 | "直接原文空格\n", 654 | "\n", 655 | "start 249 \"colors = ['red', 'green', 'red', 'blue', 'green', 'red']\\n\"\n", 656 | "直接原文空格\n", 657 | "\n", 658 | "其他白名单前代码闭合 # 简单,基本的计数方法。适合初学者起步时学习。\n", 659 | "\n", 660 | "start 252 'd = {}\\n'\n", 661 | "默认原文 for color in colors:\n", 662 | "\n", 663 | "默认原文 if color not in d:\n", 664 | "\n", 665 | "默认原文 d[color] = 0\n", 666 | "\n", 667 | "默认原文 d[color] += 1\n", 668 | "\n", 669 | "直接原文空格\n", 670 | "\n", 671 | "其他白名单前代码闭合 # {'blue': 1, 'green': 2, 'red': 3}\n", 672 | "\n", 673 | "直接原文空格\n", 674 | "\n", 675 | "原文白名单 更好的方法\n", 676 | "\n", 677 | "直接原文空格\n", 678 | "\n", 679 | "start 262 'd = {}\\n'\n", 680 | "默认原文 for color in colors:\n", 681 | "\n", 682 | "默认原文 d[color] = d.get(color, 0) + 1\n", 683 | "\n", 684 | "直接原文空格\n", 685 | "\n", 686 | "其他白名单前代码闭合 # 稍微潮点的方法,但有些坑需要注意,适合熟练的老手。\n", 687 | "\n", 688 | "start 267 'd = defaultdict(int)\\n'\n", 689 | "默认原文 for color in colors:\n", 690 | "\n", 691 | "默认原文 d[color] += 1\n", 692 | "\n", 693 | "直接原文空格\n", 694 | "\n", 695 | "end 用字典分组 — 第I部分和第II部分\n", 696 | "\n", 697 | "直接原文空格\n", 698 | "\n", 699 | "start 273 \"names = ['raymond', 'rachel', 'matthew', 'roger',\\n\"\n", 700 | "默认原文 'betty', 'melissa', 'judith', 'charlie']\n", 701 | "\n", 702 | "直接原文空格\n", 703 | "\n", 704 | "其他白名单前代码闭合 # 在这个例子,我们按name的长度分组\n", 705 | "\n", 706 | "start 277 'd = {}\\n'\n", 707 | "默认原文 for name in names:\n", 708 | "\n", 709 | "默认原文 key = len(name)\n", 710 | "\n", 711 | "默认原文 if key not in d:\n", 712 | "\n", 713 | "默认原文 d[key] = []\n", 714 | "\n", 715 | "默认原文 d[key].append(name)\n", 716 | "\n", 717 | "直接原文空格\n", 718 | "\n", 719 | "其他白名单前代码闭合 # {5: ['roger', 'betty'], 6: ['rachel', 'judith'], 7: ['raymond', 'matthew',\n", 720 | "\n", 721 | "start 285 \"'melissa', 'charlie']}\\n\"\n", 722 | "直接原文空格\n", 723 | "\n", 724 | "默认原文 d = {}\n", 725 | "\n", 726 | "默认原文 for name in names:\n", 727 | "\n", 728 | "默认原文 key = len(name)\n", 729 | "\n", 730 | "默认原文 d.setdefault(key, []).append(name)\n", 731 | "\n", 732 | "直接原文空格\n", 733 | "\n", 734 | "其他白名单前代码闭合 更好的方法\n", 735 | "\n", 736 | "直接原文空格\n", 737 | "\n", 738 | "start 294 'd = defaultdict(list)\\n'\n", 739 | "默认原文 for name in names:\n", 740 | "\n", 741 | "默认原文 key = len(name)\n", 742 | "\n", 743 | "默认原文 d[key].append(name)\n", 744 | "\n", 745 | "直接原文空格\n", 746 | "\n", 747 | "end 字典的popitem()是原子的吗?\n", 748 | "\n", 749 | "直接原文空格\n", 750 | "\n", 751 | "start 301 \"d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}\\n\"\n", 752 | "直接原文空格\n", 753 | "\n", 754 | "默认原文 while d:\n", 755 | "\n", 756 | "默认原文 key, value = d.popitem()\n", 757 | "\n", 758 | "默认原文 print key, '-->', value\n", 759 | "\n", 760 | "直接原文空格\n", 761 | "\n", 762 | "end popitem是原子的,所以多线程的时候没必要用锁包着它。\n", 763 | "\n", 764 | "直接原文空格\n", 765 | "\n", 766 | "原本中文或英文不用加 连接字典\n", 767 | "\n", 768 | "直接原文空格\n", 769 | "\n", 770 | "start 311 \"defaults = {'color': 'red', 'user': 'guest'}\\n\"\n", 771 | "默认原文 parser = argparse.ArgumentParser()\n", 772 | "\n", 773 | "默认原文 parser.add_argument('-u', '--user')\n", 774 | "\n", 775 | "默认原文 parser.add_argument('-c', '--color')\n", 776 | "\n", 777 | "默认原文 namespace = parser.parse_args([])\n", 778 | "\n", 779 | "默认原文 command_line_args = {k: v for k, v in vars(namespace).items() if v}\n", 780 | "\n", 781 | "直接原文空格\n", 782 | "\n", 783 | "其他白名单前代码闭合 # 下面是通常的作法,默认使用第一个字典,接着用环境变量覆盖它,最后用命令行参数覆盖它。\n", 784 | "\n", 785 | "原文白名单 # 然而不幸的是,这种方法拷贝数据太疯狂。\n", 786 | "\n", 787 | "start 320 'd = defaults.copy()\\n'\n", 788 | "默认原文 d.update(os.environ)\n", 789 | "\n", 790 | "默认原文 d.update(command_line_args)\n", 791 | "\n", 792 | "直接原文空格\n", 793 | "\n", 794 | "其他白名单前代码闭合 更好的方法\n", 795 | "\n", 796 | "直接原文空格\n", 797 | "\n", 798 | "start 326 'd = ChainMap(command_line_args, os.environ, defaults)\\n'\n", 799 | "直接原文空格\n", 800 | "\n", 801 | "end ChainMap在Python 3中加入。高效而优雅。\n", 802 | "\n", 803 | "直接原文空格\n", 804 | "\n", 805 | "原本中文或英文不用加 提高可读性\n", 806 | "\n", 807 | "直接原文空格\n", 808 | "\n", 809 | "原本中文或英文不用加 位置参数和下标很漂亮\n", 810 | "\n", 811 | "原本中文或英文不用加 但关键字和名称更好\n", 812 | "\n", 813 | "原本中文或英文不用加 第一种方法对计算机来说很便利\n", 814 | "\n", 815 | "原本中文或英文不用加 第二种方法和人类思考方式一致\n", 816 | "\n", 817 | "直接原文空格\n", 818 | "\n", 819 | "原本中文或英文不用加 用关键字参数提高函数调用的可读性\n", 820 | "\n", 821 | "直接原文空格\n", 822 | "\n", 823 | "start 339 \"twitter_search('@obama', False, 20, True)\\n\"\n", 824 | "直接原文空格\n", 825 | "\n", 826 | "其他白名单前代码闭合 更好的方法\n", 827 | "\n", 828 | "直接原文空格\n", 829 | "\n", 830 | "start 343 \"twitter_search('@obama', retweets=False, numtweets=20, popular=True)\\n\"\n", 831 | "直接原文空格\n", 832 | "\n", 833 | "end 第二种方法稍微(微秒级)慢一点,但为了代码的可读性和开发时间,值得。\n", 834 | "\n", 835 | "直接原文空格\n", 836 | "\n", 837 | "原本中文或英文不用加 用namedtuple提高多个返回值的可读性\n", 838 | "\n", 839 | "直接原文空格\n", 840 | "\n", 841 | "原文白名单 # 老的testmod返回值\n", 842 | "\n", 843 | "start 350 'doctest.testmod()\\n'\n", 844 | "其他白名单前代码闭合 # (0, 4)\n", 845 | "\n", 846 | "原文白名单 # 测试结果是好是坏?你看不出来,因为返回值不清晰。\n", 847 | "\n", 848 | "直接原文空格\n", 849 | "\n", 850 | "原文白名单 更好的方法\n", 851 | "\n", 852 | "直接原文空格\n", 853 | "\n", 854 | "原文白名单 # 新的testmod返回值, 一个namedtuple\n", 855 | "\n", 856 | "start 357 'doctest.testmod()\\n'\n", 857 | "其他白名单前代码闭合 # TestResults(failed=0, attempted=4)\n", 858 | "\n", 859 | "直接原文空格\n", 860 | "\n", 861 | "原本中文或英文不用加 namedtuple是tuple的子类,所以仍适用正常的元组操作,但它更友好。\n", 862 | "\n", 863 | "直接原文空格\n", 864 | "\n", 865 | "原本中文或英文不用加 创建一个nametuple\n", 866 | "\n", 867 | "直接原文空格\n", 868 | "\n", 869 | "start 364 \"TestResults = namedTuple('TestResults', ['failed', 'attempted'])\\n\"\n", 870 | "直接原文空格\n", 871 | "\n", 872 | "end unpack序列\n", 873 | "\n", 874 | "直接原文空格\n", 875 | "\n", 876 | "start 368 \"p = 'Raymond', 'Hettinger', 0x30, 'python@example.com'\\n\"\n", 877 | "直接原文空格\n", 878 | "\n", 879 | "其他白名单前代码闭合 # 其它语言的常用方法/习惯\n", 880 | "\n", 881 | "start 371 'fname = p[0]\\n'\n", 882 | "默认原文 lname = p[1]\n", 883 | "\n", 884 | "默认原文 age = p[2]\n", 885 | "\n", 886 | "默认原文 email = p[3]\n", 887 | "\n", 888 | "直接原文空格\n", 889 | "\n", 890 | "其他白名单前代码闭合 更好的方法\n", 891 | "\n", 892 | "直接原文空格\n", 893 | "\n", 894 | "start 378 'fname, lname, age, email = p\\n'\n", 895 | "直接原文空格\n", 896 | "\n", 897 | "end 第二种方法用了unpack元组,更快,可读性更好。\n", 898 | "\n", 899 | "直接原文空格\n", 900 | "\n", 901 | "原本中文或英文不用加 更新多个变量的状态\n", 902 | "\n", 903 | "直接原文空格\n", 904 | "\n", 905 | "start 384 'def fibonacci(n):\\n'\n", 906 | "默认原文 x = 0\n", 907 | "\n", 908 | "默认原文 y = 1\n", 909 | "\n", 910 | "默认原文 for i in range(n):\n", 911 | "\n", 912 | "默认原文 print x\n", 913 | "\n", 914 | "默认原文 t = y\n", 915 | "\n", 916 | "默认原文 y = x + y\n", 917 | "\n", 918 | "默认原文 x = t\n", 919 | "\n", 920 | "直接原文空格\n", 921 | "\n", 922 | "其他白名单前代码闭合 更好的方法\n", 923 | "\n", 924 | "直接原文空格\n", 925 | "\n", 926 | "start 395 'def fibonacci(n):\\n'\n", 927 | "默认原文 x, y = 0, 1\n", 928 | "\n", 929 | "默认原文 for i in range(n):\n", 930 | "\n", 931 | "默认原文 print x\n", 932 | "\n", 933 | "默认原文 x, y = y, x + y\n", 934 | "\n", 935 | "直接原文空格\n", 936 | "\n", 937 | "end 第一种方法的问题\n", 938 | "\n", 939 | "直接原文空格\n", 940 | "\n", 941 | "原本中文或英文不用加 x和y是状态,状态应该在一次操作中更新,分几行的话状态会互相对不上,这经常是bug的源头。\n", 942 | "\n", 943 | "原本中文或英文不用加 操作有顺序要求\n", 944 | "\n", 945 | "原本中文或英文不用加 太底层太细节\n", 946 | "\n", 947 | "直接原文空格\n", 948 | "\n", 949 | "原本中文或英文不用加 第二种方法抽象层级更高,没有操作顺序出错的风险而且更效率更高。\n", 950 | "\n", 951 | "直接原文空格\n", 952 | "\n", 953 | "原本中文或英文不用加 同时状态更新\n", 954 | "\n", 955 | "直接原文空格\n", 956 | "\n", 957 | "start 411 'tmp_x = x + dx * t\\n'\n", 958 | "默认原文 tmp_y = y + dy * t\n", 959 | "\n", 960 | "默认原文 tmp_dx = influence(m, x, y, dx, dy, partial='x')\n", 961 | "\n", 962 | "默认原文 tmp_dy = influence(m, x, y, dx, dy, partial='y')\n", 963 | "\n", 964 | "默认原文 x = tmp_x\n", 965 | "\n", 966 | "默认原文 y = tmp_y\n", 967 | "\n", 968 | "默认原文 dx = tmp_dx\n", 969 | "\n", 970 | "默认原文 dy = tmp_dy\n", 971 | "\n", 972 | "直接原文空格\n", 973 | "\n", 974 | "其他白名单前代码闭合 更好的方法\n", 975 | "\n", 976 | "直接原文空格\n", 977 | "\n", 978 | "start 422 'x, y, dx, dy = (x + dx * t,\\n'\n", 979 | "默认原文 y + dy * t,\n", 980 | "\n", 981 | "默认原文 influence(m, x, y, dx, dy, partial='x'),\n", 982 | "\n", 983 | "默认原文 influence(m, x, y, dx, dy, partial='y'))\n", 984 | "\n", 985 | "直接原文空格\n", 986 | "\n", 987 | "end 效率\n", 988 | "\n", 989 | "直接原文空格\n", 990 | "\n", 991 | "原本中文或英文不用加 优化的基本原则\n", 992 | "\n", 993 | "原本中文或英文不用加 除非必要,别无故移动数据\n", 994 | "\n", 995 | "原本中文或英文不用加 稍微注意一下用线性的操作取代O(n**2)的操作\n", 996 | "\n", 997 | "直接原文空格\n", 998 | "\n", 999 | "原本中文或英文不用加 总的来说,不要无故移动数据\n", 1000 | "\n", 1001 | "直接原文空格\n", 1002 | "\n", 1003 | "原本中文或英文不用加 连接字符串\n", 1004 | "\n", 1005 | "直接原文空格\n", 1006 | "\n", 1007 | "start 437 \"names = ['raymond', 'rachel', 'matthew', 'roger',\\n\"\n", 1008 | "默认原文 'betty', 'melissa', 'judith', 'charlie']\n", 1009 | "\n", 1010 | "直接原文空格\n", 1011 | "\n", 1012 | "默认原文 s = names[0]\n", 1013 | "\n", 1014 | "默认原文 for name in names[1:]:\n", 1015 | "\n", 1016 | "默认原文 s += ', ' + name\n", 1017 | "\n", 1018 | "默认原文 print s\n", 1019 | "\n", 1020 | "直接原文空格\n", 1021 | "\n", 1022 | "其他白名单前代码闭合 更好的方法\n", 1023 | "\n", 1024 | "直接原文空格\n", 1025 | "\n", 1026 | "start 447 \"print ', '.join(names)\\n\"\n", 1027 | "直接原文空格\n", 1028 | "\n", 1029 | "end 更新序列\n", 1030 | "\n", 1031 | "直接原文空格\n", 1032 | "\n", 1033 | "start 451 \"names = ['raymond', 'rachel', 'matthew', 'roger',\\n\"\n", 1034 | "默认原文 'betty', 'melissa', 'judith', 'charlie']\n", 1035 | "\n", 1036 | "直接原文空格\n", 1037 | "\n", 1038 | "默认原文 del names[0]\n", 1039 | "\n", 1040 | "其他白名单前代码闭合 # 下面的代码标志着你用错了数据结构\n", 1041 | "\n", 1042 | "start 456 'names.pop(0)\\n'\n", 1043 | "默认原文 names.insert(0, 'mark')\n", 1044 | "\n", 1045 | "直接原文空格\n", 1046 | "\n", 1047 | "其他白名单前代码闭合 更好的方法\n", 1048 | "\n", 1049 | "直接原文空格\n", 1050 | "\n", 1051 | "start 461 \"names = deque(['raymond', 'rachel', 'matthew', 'roger',\\n\"\n", 1052 | "默认原文 'betty', 'melissa', 'judith', 'charlie'])\n", 1053 | "\n", 1054 | "直接原文空格\n", 1055 | "\n", 1056 | "其他白名单前代码闭合 # 用deque更有效率\n", 1057 | "\n", 1058 | "start 465 'del names[0]\\n'\n", 1059 | "默认原文 names.popleft()\n", 1060 | "\n", 1061 | "默认原文 names.appendleft('mark')\n", 1062 | "\n", 1063 | "直接原文空格\n", 1064 | "\n", 1065 | "end 装饰器和上下文管理\n", 1066 | "\n", 1067 | "直接原文空格\n", 1068 | "\n", 1069 | "原本中文或英文不用加 用于把业务和管理的逻辑分开\n", 1070 | "\n", 1071 | "原本中文或英文不用加 分解代码和提高代码重用性的干净优雅的好工具\n", 1072 | "\n", 1073 | "原本中文或英文不用加 起个好名字很关键\n", 1074 | "\n", 1075 | "原本中文或英文不用加 记住蜘蛛侠的格言:能力越大,责任越大\n", 1076 | "\n", 1077 | "直接原文空格\n", 1078 | "\n", 1079 | "原本中文或英文不用加 使用装饰器分离出管理逻辑\n", 1080 | "\n", 1081 | "直接原文空格\n", 1082 | "\n", 1083 | "原文白名单 # 混着业务和管理逻辑,无法重用\n", 1084 | "\n", 1085 | "start 479 'def web_lookup(url, saved={}):\\n'\n", 1086 | "默认原文 if url in saved:\n", 1087 | "\n", 1088 | "默认原文 return saved[url]\n", 1089 | "\n", 1090 | "默认原文 page = urllib.urlopen(url).read()\n", 1091 | "\n", 1092 | "默认原文 saved[url] = page\n", 1093 | "\n", 1094 | "默认原文 return page\n", 1095 | "\n", 1096 | "直接原文空格\n", 1097 | "\n", 1098 | "其他白名单前代码闭合 更好的方法\n", 1099 | "\n", 1100 | "直接原文空格\n", 1101 | "\n", 1102 | "start 488 '@cache\\n'\n", 1103 | "默认原文 def web_lookup(url):\n", 1104 | "\n", 1105 | "默认原文 return urllib.urlopen(url).read()\n", 1106 | "\n", 1107 | "直接原文空格\n", 1108 | "\n", 1109 | "end 注意:Python 3.2开始加入了functools.lru_cache解决这个问题。\n", 1110 | "\n", 1111 | "直接原文空格\n", 1112 | "\n", 1113 | "原本中文或英文不用加 分离临时上下文\n", 1114 | "\n", 1115 | "直接原文空格\n", 1116 | "\n", 1117 | "原文白名单 # 保存旧的,创建新的\n", 1118 | "\n", 1119 | "start 497 'old_context = getcontext().copy()\\n'\n", 1120 | "默认原文 getcontext().prec = 50\n", 1121 | "\n", 1122 | "默认原文 print Decimal(355) / Decimal(113)\n", 1123 | "\n", 1124 | "默认原文 setcontext(old_context)\n", 1125 | "\n", 1126 | "直接原文空格\n", 1127 | "\n", 1128 | "其他白名单前代码闭合 更好的方法\n", 1129 | "\n", 1130 | "直接原文空格\n", 1131 | "\n", 1132 | "start 504 'with localcontext(Context(prec=50)):\\n'\n", 1133 | "默认原文 print Decimal(355) / Decimal(113)\n", 1134 | "\n", 1135 | "直接原文空格\n", 1136 | "\n", 1137 | "end 译注:示例代码在使用标准库decimal,这个库已经实现好了localcontext。\n", 1138 | "\n", 1139 | "直接原文空格\n", 1140 | "\n", 1141 | "原本中文或英文不用加 如何打开关闭文件\n", 1142 | "\n", 1143 | "直接原文空格\n", 1144 | "\n", 1145 | "start 511 \"f = open('data.txt')\\n\"\n", 1146 | "默认原文 try:\n", 1147 | "\n", 1148 | "默认原文 data = f.read()\n", 1149 | "\n", 1150 | "默认原文 finally:\n", 1151 | "\n", 1152 | "默认原文 f.close()\n", 1153 | "\n", 1154 | "直接原文空格\n", 1155 | "\n", 1156 | "其他白名单前代码闭合 更好的方法\n", 1157 | "\n", 1158 | "直接原文空格\n", 1159 | "\n", 1160 | "start 519 \"with open('data.txt') as f:\\n\"\n", 1161 | "默认原文 data = f.read()\n", 1162 | "\n", 1163 | "直接原文空格\n", 1164 | "\n", 1165 | "end 如何使用锁\n", 1166 | "\n", 1167 | "直接原文空格\n", 1168 | "\n", 1169 | "原文白名单 # 创建锁\n", 1170 | "\n", 1171 | "start 525 'lock = threading.Lock()\\n'\n", 1172 | "直接原文空格\n", 1173 | "\n", 1174 | "其他白名单前代码闭合 # 使用锁的老方法\n", 1175 | "\n", 1176 | "start 528 'lock.acquire()\\n'\n", 1177 | "默认原文 try:\n", 1178 | "\n", 1179 | "默认原文 print 'Critical section 1'\n", 1180 | "\n", 1181 | "默认原文 print 'Critical section 2'\n", 1182 | "\n", 1183 | "默认原文 finally:\n", 1184 | "\n", 1185 | "默认原文 lock.release()\n", 1186 | "\n", 1187 | "直接原文空格\n", 1188 | "\n", 1189 | "其他白名单前代码闭合 更好的方法\n", 1190 | "\n", 1191 | "直接原文空格\n", 1192 | "\n", 1193 | "原文白名单 # 使用锁的新方法\n", 1194 | "\n", 1195 | "start 538 'with lock:\\n'\n", 1196 | "默认原文 print 'Critical section 1'\n", 1197 | "\n", 1198 | "默认原文 print 'Critical section 2'\n", 1199 | "\n", 1200 | "直接原文空格\n", 1201 | "\n", 1202 | "end 分离出临时的上下文\n", 1203 | "\n", 1204 | "直接原文空格\n", 1205 | "\n", 1206 | "start 544 'try:\\n'\n", 1207 | "默认原文 os.remove('somefile.tmp')\n", 1208 | "\n", 1209 | "默认原文 except OSError:\n", 1210 | "\n", 1211 | "默认原文 pass\n", 1212 | "\n", 1213 | "直接原文空格\n", 1214 | "\n", 1215 | "其他白名单前代码闭合 更好的方法\n", 1216 | "\n", 1217 | "直接原文空格\n", 1218 | "\n", 1219 | "start 551 'with ignored(OSError):\\n'\n", 1220 | "默认原文 os.remove('somefile.tmp')\n", 1221 | "\n", 1222 | "直接原文空格\n", 1223 | "\n", 1224 | "end ignored是Python 3.4加入的, 文档。\n", 1225 | "\n", 1226 | "直接原文空格\n", 1227 | "\n", 1228 | "原本中文或英文不用加 注意:ignored 实际上在标准库叫suppress(译注:contextlib.supress).\n", 1229 | "\n", 1230 | "直接原文空格\n", 1231 | "\n", 1232 | "原本中文或英文不用加 试试创建你自己的ignored上下文管理器。\n", 1233 | "\n", 1234 | "直接原文空格\n", 1235 | "\n", 1236 | "start 560 '@contextmanager\\n'\n", 1237 | "默认原文 def ignored(*exceptions):\n", 1238 | "\n", 1239 | "默认原文 try:\n", 1240 | "\n", 1241 | "默认原文 yield\n", 1242 | "\n", 1243 | "默认原文 except exceptions:\n", 1244 | "\n", 1245 | "默认原文 pass\n", 1246 | "\n", 1247 | "直接原文空格\n", 1248 | "\n", 1249 | "end 把它放在你的工具目录,你也可以忽略异常\n", 1250 | "\n", 1251 | "直接原文空格\n", 1252 | "\n", 1253 | "原本中文或英文不用加 译注:contextmanager在标准库contextlib中,通过装饰生成器函数,省去用__enter__和__exit__写上下文管理器。详情请看文档。\n", 1254 | "\n", 1255 | "直接原文空格\n", 1256 | "\n", 1257 | "原本中文或英文不用加 分离临时上下文\n", 1258 | "\n", 1259 | "直接原文空格\n", 1260 | "\n", 1261 | "原文白名单 # 临时把标准输出重定向到一个文件,然后再恢复正常\n", 1262 | "\n", 1263 | "start 574 \"with open('help.txt', 'w') as f:\\n\"\n", 1264 | "默认原文 oldstdout = sys.stdout\n", 1265 | "\n", 1266 | "默认原文 sys.stdout = f\n", 1267 | "\n", 1268 | "默认原文 try:\n", 1269 | "\n", 1270 | "默认原文 help(pow)\n", 1271 | "\n", 1272 | "默认原文 finally:\n", 1273 | "\n", 1274 | "默认原文 sys.stdout = oldstdout\n", 1275 | "\n", 1276 | "直接原文空格\n", 1277 | "\n", 1278 | "end 更好的写法\n", 1279 | "\n", 1280 | "直接原文空格\n", 1281 | "\n", 1282 | "start 584 \"with open('help.txt', 'w') as f:\\n\"\n", 1283 | "默认原文 with redirect_stdout(f):\n", 1284 | "\n", 1285 | "默认原文 help(pow)\n", 1286 | "\n", 1287 | "直接原文空格\n", 1288 | "\n", 1289 | "end redirect_stdout在Python 3.4加入(译注:contextlib.redirect_stdout), bug反馈。\n", 1290 | "\n", 1291 | "直接原文空格\n", 1292 | "\n", 1293 | "原本中文或英文不用加 实现你自己的redirect_stdout上下文管理器。\n", 1294 | "\n", 1295 | "直接原文空格\n", 1296 | "\n", 1297 | "start 592 '@contextmanager\\n'\n", 1298 | "默认原文 def redirect_stdout(fileobj):\n", 1299 | "\n", 1300 | "默认原文 oldstdout = sys.stdout\n", 1301 | "\n", 1302 | "默认原文 sys.stdout = fileobj\n", 1303 | "\n", 1304 | "默认原文 try:\n", 1305 | "\n", 1306 | "默认原文 yield fieldobj\n", 1307 | "\n", 1308 | "默认原文 finally:\n", 1309 | "\n", 1310 | "默认原文 sys.stdout = oldstdout\n", 1311 | "\n", 1312 | "直接原文空格\n", 1313 | "\n", 1314 | "end 简洁的单句表达\n", 1315 | "\n", 1316 | "直接原文空格\n", 1317 | "\n", 1318 | "原本中文或英文不用加 两个冲突的原则:\n", 1319 | "\n", 1320 | "直接原文空格\n", 1321 | "\n", 1322 | "原本中文或英文不用加 一行不要有太多逻辑\n", 1323 | "\n", 1324 | "原本中文或英文不用加 不要把单一的想法拆分成多个部分\n", 1325 | "\n", 1326 | "直接原文空格\n", 1327 | "\n", 1328 | "原本中文或英文不用加 Raymond的原则:\n", 1329 | "\n", 1330 | "直接原文空格\n", 1331 | "\n", 1332 | "原本中文或英文不用加 一行代码的逻辑等价于一句自然语言\n", 1333 | "\n", 1334 | "直接原文空格\n", 1335 | "\n", 1336 | "原本中文或英文不用加 列表解析和生成器\n", 1337 | "\n", 1338 | "直接原文空格\n", 1339 | "\n", 1340 | "start 614 'result = []\\n'\n", 1341 | "默认原文 for i in range(10):\n", 1342 | "\n", 1343 | "默认原文 s = i ** 2\n", 1344 | "\n", 1345 | "默认原文 result.append(s)\n", 1346 | "\n", 1347 | "默认原文 print sum(result)\n", 1348 | "\n", 1349 | "直接原文空格\n", 1350 | "\n", 1351 | "其他白名单前代码闭合 更好的方法\n", 1352 | "\n", 1353 | "直接原文空格\n", 1354 | "\n", 1355 | "start 622 'print sum(i**2 for i in xrange(10))\\n'\n", 1356 | "直接原文空格\n", 1357 | "\n", 1358 | "end 第一种方法说的是你在做什么,第二种方法说的是你想要什么。\n", 1359 | "\n" 1360 | ] 1361 | } 1362 | ], 1363 | "source": [ 1364 | "match_value_s = []\n", 1365 | "\n", 1366 | "for k, line in enumerate(lines):\n", 1367 | " for re_value in res:\n", 1368 | " \n", 1369 | " if line.isspace():\n", 1370 | " # \\n 换行 直接 插入\n", 1371 | " match_value_s.append(line)\n", 1372 | " print('直接原文空格\\n',)\n", 1373 | " break\n", 1374 | " \n", 1375 | " match_value = re.match( re_value, line.strip(), re.M|re.I)\n", 1376 | " \n", 1377 | " if match_value:\n", 1378 | " \n", 1379 | " # 代码开始—结束的区域固定\n", 1380 | " # ``` py\n", 1381 | " # ```\n", 1382 | " if py_is and re_value == r'``` py':\n", 1383 | " match_value_s.append(input_value['end_code'] + line)\n", 1384 | " print('两个```py 代码',line)\n", 1385 | " py_is_fun('```')\n", 1386 | " break\n", 1387 | " elif re_value == r'``` py':\n", 1388 | " py_is_fun(re_value)\n", 1389 | " match_value_s.append(line)\n", 1390 | " print('本来开始代码',line)\n", 1391 | " break\n", 1392 | " elif re_value == r'```':\n", 1393 | " match_value_s.append(line)\n", 1394 | " print('本来结束代码',line)\n", 1395 | " py_is_fun('```')\n", 1396 | " break\n", 1397 | " elif py_is:\n", 1398 | " match_value_s.append(input_value['end_code'] + line)\n", 1399 | " print('其他白名单前代码闭合',line)\n", 1400 | " py_is_fun('```')\n", 1401 | " break\n", 1402 | " else:\n", 1403 | " match_value_s.append(line)\n", 1404 | " print('原文白名单',line)\n", 1405 | " break\n", 1406 | " \n", 1407 | " else:\n", 1408 | " \n", 1409 | " # 有中文有英文,不做处理\n", 1410 | " # 多个中文片段\n", 1411 | " if is_en_zh(line) is not 0 or is_zh(line) > 1:\n", 1412 | " if py_is:\n", 1413 | " match_value_s.append(input_value['end_code'] + line)\n", 1414 | " py_is_fun('```')\n", 1415 | " print('end',line)\n", 1416 | " \n", 1417 | " else:\n", 1418 | " match_value_s.append(line)\n", 1419 | " print('原本中文或英文不用加',line)\n", 1420 | " \n", 1421 | " # 单个中文片段,加 h2\n", 1422 | " elif is_zh(line) and is_zh(line) <= 1:\n", 1423 | " if py_is:\n", 1424 | " match_value_s.append(input_value['end_code'] + input_value['h2'] + line)\n", 1425 | " py_is_fun('```')\n", 1426 | " print('加h2+end',line)\n", 1427 | " \n", 1428 | " else:\n", 1429 | " match_value_s.append(input_value['h2'] + line)\n", 1430 | " print('加h2',line) \n", 1431 | " # 默认\n", 1432 | " elif py_is == False:\n", 1433 | " \n", 1434 | " match_value_s.append( input_value['start_tcode'] + line)\n", 1435 | " py_is_fun('``` py') \n", 1436 | " print('start', str(k), repr(line) )\n", 1437 | " \n", 1438 | " else:\n", 1439 | " match_value_s.append(line)\n", 1440 | " print('默认原文',line)\n", 1441 | " \n", 1442 | " \n", 1443 | " \n", 1444 | " \n", 1445 | " " 1446 | ] 1447 | }, 1448 | { 1449 | "cell_type": "code", 1450 | "execution_count": 10, 1451 | "metadata": { 1452 | "ExecuteTime": { 1453 | "end_time": "2017-09-26T12:40:00.592042Z", 1454 | "start_time": "2017-09-26T12:40:00.504785Z" 1455 | }, 1456 | "collapsed": false 1457 | }, 1458 | "outputs": [ 1459 | { 1460 | "name": "stdout", 1461 | "output_type": "stream", 1462 | "text": [ 1463 | "---\n", 1464 | "\n", 1465 | "title: 让你的Python优雅\n", 1466 | "\n", 1467 | "``` py\n", 1468 | "thumbnail:\n", 1469 | "\n", 1470 | "'http://tse2.mm.bing.net/th?id=OIP.HMoLaA0mOSlTzJRGppa0ZQEgEs&pid=15.1'\n", 1471 | "\n", 1472 | "date: 2017-09-16 09:28:28\n", 1473 | "\n", 1474 | "tags: [python, ]\n", 1475 | "\n", 1476 | "banner:\n", 1477 | "\n", 1478 | "```\n", 1479 | "---\n", 1480 | "\n", 1481 | "\n", 1482 | "\n", 1483 | "参考译文来自:www.lightxue.com/transforming-code-into-beautiful-idiomatic-python\n", 1484 | "\n", 1485 | "\n", 1486 | "\n", 1487 | "在Python社区文化的浇灌下,演化出了一种独特的代码风格,去指导如何正确地使用Python,这就是常说的pythonic。\n", 1488 | "\n", 1489 | "\n", 1490 | "\n", 1491 | "Raymond Hettinger是Python核心开发者,本文提到的许多特性都是他开发的。同时他也是Python社区热忱的布道师,不遗余力地传授pythoni\n", 1492 | "\n", 1493 | "c之道。这篇文章是网友Jeff Paine整理的他在2013年美国的PyCon的演讲的笔记。\n", 1494 | "\n", 1495 | "\n", 1496 | "\n", 1497 | "---\n", 1498 | "\n", 1499 | "\n", 1500 | "\n", 1501 | "可下载 jupyter\n", 1502 | "\n", 1503 | "点击下载\n", 1504 | "\n", 1505 | "\n", 1506 | "\n", 1507 | "以下正文\n", 1508 | "\n", 1509 | "\n", 1510 | "\n", 1511 | "---\n", 1512 | "\n", 1513 | "\n", 1514 | "\n", 1515 | "## 遍历一个范围内的数字\n", 1516 | "\n", 1517 | "\n", 1518 | "\n", 1519 | "``` py\n", 1520 | "\n", 1521 | "for i in [0, 1, 2, 3, 4, 5]:\n", 1522 | "\n", 1523 | " print i ** 2\n", 1524 | "\n", 1525 | " \n", 1526 | "\n", 1527 | "for i in range(6):\n", 1528 | "\n", 1529 | " print i ** 2\n", 1530 | "\n", 1531 | "```\n", 1532 | "\n", 1533 | "\n", 1534 | "\n", 1535 | "更好的方法\n", 1536 | "\n", 1537 | "\n", 1538 | "\n", 1539 | "``` py\n", 1540 | "\n", 1541 | "for i in xrange(6):\n", 1542 | "\n", 1543 | " print i ** 2\n", 1544 | "\n", 1545 | "```\n", 1546 | "\n", 1547 | "\n", 1548 | "\n", 1549 | "xrange会返回一个迭代器,用来一次\n", 1550 | "\n", 1551 | "遍历一个范围。这种方式会比range更省内存。xrange在Python 3中已经改名为range。\n", 1552 | "\n", 1553 | "\n", 1554 | "\n", 1555 | "## 遍历一个集合\n", 1556 | "\n", 1557 | "\n", 1558 | "\n", 1559 | "``` py\n", 1560 | "\n", 1561 | "colors = ['red', 'green', 'blue', 'yellow']\n", 1562 | "\n", 1563 | " \n", 1564 | "\n", 1565 | "for i in range(len(colors)):\n", 1566 | "\n", 1567 | " print colors[i]\n", 1568 | "\n", 1569 | "```\n", 1570 | "\n", 1571 | "\n", 1572 | "\n", 1573 | "更好的方法\n", 1574 | "\n", 1575 | "\n", 1576 | "\n", 1577 | "``` py\n", 1578 | "\n", 1579 | "for color in colors:\n", 1580 | "\n", 1581 | " print color\n", 1582 | "\n", 1583 | "```\n", 1584 | "\n", 1585 | "\n", 1586 | "\n", 1587 | "## 反向遍历\n", 1588 | "\n", 1589 | "\n", 1590 | "\n", 1591 | "``` py\n", 1592 | "\n", 1593 | "colors = ['red', 'green', 'blue', 'yellow']\n", 1594 | "\n", 1595 | " \n", 1596 | "\n", 1597 | "for i in range(len(colors)-1, -1, -1):\n", 1598 | "\n", 1599 | " print colors[i]\n", 1600 | "\n", 1601 | "```\n", 1602 | "\n", 1603 | "\n", 1604 | "\n", 1605 | "更好的方法\n", 1606 | "\n", 1607 | "\n", 1608 | "\n", 1609 | "``` py\n", 1610 | "\n", 1611 | "for color in reversed(colors):\n", 1612 | "\n", 1613 | " print color\n", 1614 | "\n", 1615 | "```\n", 1616 | "\n", 1617 | "\n", 1618 | "\n", 1619 | "\n", 1620 | "\n", 1621 | "\n", 1622 | "\n", 1623 | "## 遍历一个集合及其下标\n", 1624 | "\n", 1625 | "\n", 1626 | "\n", 1627 | "``` py\n", 1628 | "\n", 1629 | "colors = ['red', 'green', 'blue', 'yellow']\n", 1630 | "\n", 1631 | " \n", 1632 | "\n", 1633 | "for i in range(len(colors)):\n", 1634 | "\n", 1635 | " print i, '--->', colors[i]\n", 1636 | "\n", 1637 | "```\n", 1638 | "\n", 1639 | "\n", 1640 | "\n", 1641 | "更好的方法\n", 1642 | "\n", 1643 | "\n", 1644 | "\n", 1645 | "``` py\n", 1646 | "\n", 1647 | "for i, color in enumerate(colors):\n", 1648 | "\n", 1649 | " print i, '--->', color\n", 1650 | "\n", 1651 | "```\n", 1652 | "\n", 1653 | "\n", 1654 | "\n", 1655 | "这种写法效率高,优雅,而且帮你省去亲自创建和自增下标。\n", 1656 | "\n", 1657 | "\n", 1658 | "\n", 1659 | "当你发现你在操作集合的下标时,你很有可能在做错事。\n", 1660 | "\n", 1661 | "\n", 1662 | "\n", 1663 | "\n", 1664 | "\n", 1665 | "## 遍历两个集合\n", 1666 | "\n", 1667 | "\n", 1668 | "\n", 1669 | "``` py\n", 1670 | "names = ['raymond', 'rachel', 'matthew']\n", 1671 | "\n", 1672 | "colors = ['red', 'green', 'blue', 'yellow']\n", 1673 | "\n", 1674 | "\n", 1675 | "\n", 1676 | "n = min(len(names), len(colors))\n", 1677 | "\n", 1678 | "for i in range(n):\n", 1679 | "\n", 1680 | " print names[i], '--->', colors[i]\n", 1681 | "\n", 1682 | "\n", 1683 | "\n", 1684 | "for name, color in zip(names, colors):\n", 1685 | "\n", 1686 | " print name, '--->', color\n", 1687 | "\n", 1688 | "\n", 1689 | "\n", 1690 | "```\n", 1691 | "更好的方法\n", 1692 | "\n", 1693 | "\n", 1694 | "\n", 1695 | "``` py\n", 1696 | "for name, color in izip(names, colors):\n", 1697 | "\n", 1698 | " print name, '--->', color\n", 1699 | "\n", 1700 | "\n", 1701 | "\n", 1702 | "```\n", 1703 | "zip在内存中生成一个新的列表,需要更多的内存。izip比zip效率更高。\n", 1704 | "\n", 1705 | "\n", 1706 | "\n", 1707 | "注意:在Python 3中,izip改名为zip,并替换了原来的zip成为内置函数。\n", 1708 | "\n", 1709 | "\n", 1710 | "\n", 1711 | "有序地遍历\n", 1712 | "\n", 1713 | "\n", 1714 | "\n", 1715 | "``` py\n", 1716 | "colors = ['red', 'green', 'blue', 'yellow']\n", 1717 | "\n", 1718 | "\n", 1719 | "\n", 1720 | "```\n", 1721 | "# 正序\n", 1722 | "\n", 1723 | "``` py\n", 1724 | "for color in sorted(colors):\n", 1725 | "\n", 1726 | " print colors\n", 1727 | "\n", 1728 | "\n", 1729 | "\n", 1730 | "```\n", 1731 | "# 倒序\n", 1732 | "\n", 1733 | "``` py\n", 1734 | "for color in sorted(colors, reverse=True):\n", 1735 | "\n", 1736 | " print colors\n", 1737 | "\n", 1738 | "\n", 1739 | "\n", 1740 | "```\n", 1741 | "自定义排序顺序\n", 1742 | "\n", 1743 | "\n", 1744 | "\n", 1745 | "``` py\n", 1746 | "colors = ['red', 'green', 'blue', 'yellow']\n", 1747 | "\n", 1748 | "\n", 1749 | "\n", 1750 | "def compare_length(c1, c2):\n", 1751 | "\n", 1752 | " if len(c1) < len(c2): return -1\n", 1753 | "\n", 1754 | " if len(c1) > len(c2): return 1\n", 1755 | "\n", 1756 | " return 0\n", 1757 | "\n", 1758 | "\n", 1759 | "\n", 1760 | "print sorted(colors, cmp=compare_length)\n", 1761 | "\n", 1762 | "\n", 1763 | "\n", 1764 | "```\n", 1765 | "更好的方法\n", 1766 | "\n", 1767 | "\n", 1768 | "\n", 1769 | "``` py\n", 1770 | "print sorted(colors, key=len)\n", 1771 | "\n", 1772 | "\n", 1773 | "\n", 1774 | "```\n", 1775 | "第一种方法效率低而且写起来很不爽。另外,Python 3已经不支持比较函数了。\n", 1776 | "\n", 1777 | "\n", 1778 | "\n", 1779 | "调用一个函数直到遇到标记值\n", 1780 | "\n", 1781 | "\n", 1782 | "\n", 1783 | "``` py\n", 1784 | "blocks = []\n", 1785 | "\n", 1786 | "while True:\n", 1787 | "\n", 1788 | " block = f.read(32)\n", 1789 | "\n", 1790 | " if block == '':\n", 1791 | "\n", 1792 | " break\n", 1793 | "\n", 1794 | " blocks.append(block)\n", 1795 | "\n", 1796 | "\n", 1797 | "\n", 1798 | "```\n", 1799 | "更好的方法\n", 1800 | "\n", 1801 | "\n", 1802 | "\n", 1803 | "``` py\n", 1804 | "blocks = []\n", 1805 | "\n", 1806 | "for block in iter(partial(f.read, 32), ''):\n", 1807 | "\n", 1808 | " blocks.append(block)\n", 1809 | "\n", 1810 | "\n", 1811 | "\n", 1812 | "```\n", 1813 | "iter接受两个参数。第一个是你反复调用的函数,第二个是标记值。\n", 1814 | "\n", 1815 | "\n", 1816 | "\n", 1817 | "译注:这个例子里不太能看出来方法二的优势,甚至觉得partial让代码可读性更差了。方法二的优势在于iter的返回值是个迭代器,迭代器能用在各种地方,set,s\n", 1818 | "\n", 1819 | "``` py\n", 1820 | "orted,min,max,heapq,sum……\n", 1821 | "\n", 1822 | "\n", 1823 | "\n", 1824 | "```\n", 1825 | "在循环内识别多个退出点\n", 1826 | "\n", 1827 | "\n", 1828 | "\n", 1829 | "``` py\n", 1830 | "def find(seq, target):\n", 1831 | "\n", 1832 | " found = False\n", 1833 | "\n", 1834 | " for i, value in enumerate(seq):\n", 1835 | "\n", 1836 | " if value == target:\n", 1837 | "\n", 1838 | " found = True\n", 1839 | "\n", 1840 | " break\n", 1841 | "\n", 1842 | " if not found:\n", 1843 | "\n", 1844 | " return -1\n", 1845 | "\n", 1846 | " return i\n", 1847 | "\n", 1848 | "\n", 1849 | "\n", 1850 | "```\n", 1851 | "更好的方法\n", 1852 | "\n", 1853 | "\n", 1854 | "\n", 1855 | "``` py\n", 1856 | "def find(seq, target):\n", 1857 | "\n", 1858 | " for i, value in enumerate(seq):\n", 1859 | "\n", 1860 | " if value == target:\n", 1861 | "\n", 1862 | " break\n", 1863 | "\n", 1864 | " else:\n", 1865 | "\n", 1866 | " return -1\n", 1867 | "\n", 1868 | " return i\n", 1869 | "\n", 1870 | "\n", 1871 | "\n", 1872 | "```\n", 1873 | "for执行完所有的循环后就会执行else。\n", 1874 | "\n", 1875 | "\n", 1876 | "\n", 1877 | "译注:刚了解for-else语法时会困惑,什么情况下会执行到else里。有两种方法去理解else。传统的方法是把for看作if,当for后面的条件为False时\n", 1878 | "\n", 1879 | "执行else。其实条件为False时,就是for循环没被break出去,把所有循环都跑完的时候。所以另一种方法就是把else记成nobreak,当for没有被b\n", 1880 | "\n", 1881 | "reak,那么循环结束时会进入到else。\n", 1882 | "\n", 1883 | "\n", 1884 | "\n", 1885 | "遍历字典的key\n", 1886 | "\n", 1887 | "\n", 1888 | "\n", 1889 | "``` py\n", 1890 | "d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}\n", 1891 | "\n", 1892 | "\n", 1893 | "\n", 1894 | "for k in d:\n", 1895 | "\n", 1896 | " print k\n", 1897 | "\n", 1898 | "\n", 1899 | "\n", 1900 | "for k in d.keys():\n", 1901 | "\n", 1902 | " if k.startswith('r'):\n", 1903 | "\n", 1904 | " del d[k]\n", 1905 | "\n", 1906 | "\n", 1907 | "\n", 1908 | "```\n", 1909 | "什么时候应该使用第二种而不是第一种方法?当你需要修改字典的时候。\n", 1910 | "\n", 1911 | "\n", 1912 | "\n", 1913 | "如果你在迭代一个东西的时候修改它,那就是在冒天下之大不韪,接下来发生什么都活该。\n", 1914 | "\n", 1915 | "\n", 1916 | "\n", 1917 | "d.keys()把字典里所有的key都复制到一个列表里。然后你就可以修改字典了。\n", 1918 | "\n", 1919 | "\n", 1920 | "\n", 1921 | "注意:如果在Python\n", 1922 | "\n", 1923 | "3里迭代一个字典你得显示地写:list(d.keys()),因为d.keys()返回的是一个“字典视图”(一个提供字典key的动态视图的迭代器)。详情请看文档。\n", 1924 | "\n", 1925 | "\n", 1926 | "\n", 1927 | "遍历一个字典的key和value\n", 1928 | "\n", 1929 | "\n", 1930 | "\n", 1931 | "# 并不快,每次必须要重新哈希并做一次查找\n", 1932 | "\n", 1933 | "``` py\n", 1934 | "for k in d:\n", 1935 | "\n", 1936 | " print k, '--->', d[k]\n", 1937 | "\n", 1938 | "\n", 1939 | "\n", 1940 | "```\n", 1941 | "# 产生一个很大的列表\n", 1942 | "\n", 1943 | "``` py\n", 1944 | "for k, v in d.items():\n", 1945 | "\n", 1946 | " print k, '--->', v\n", 1947 | "\n", 1948 | "\n", 1949 | "\n", 1950 | "```\n", 1951 | "更好的方法\n", 1952 | "\n", 1953 | "\n", 1954 | "\n", 1955 | "``` py\n", 1956 | "for k, v in d.iteritems():\n", 1957 | "\n", 1958 | " print k, '--->', v\n", 1959 | "\n", 1960 | "\n", 1961 | "\n", 1962 | "```\n", 1963 | "iteritems()更好是因为它返回了一个迭代器。\n", 1964 | "\n", 1965 | "\n", 1966 | "\n", 1967 | "注意:Python 3已经没有iteritems()了,items()的行为和iteritems()很接近。详情请看文档。\n", 1968 | "\n", 1969 | "\n", 1970 | "\n", 1971 | "用key-value对构建字典\n", 1972 | "\n", 1973 | "\n", 1974 | "\n", 1975 | "``` py\n", 1976 | "names = ['raymond', 'rachel', 'matthew']\n", 1977 | "\n", 1978 | "colors = ['red', 'green', 'blue']\n", 1979 | "\n", 1980 | "\n", 1981 | "\n", 1982 | "d = dict(izip(names, colors))\n", 1983 | "\n", 1984 | "```\n", 1985 | "# {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}\n", 1986 | "\n", 1987 | "\n", 1988 | "\n", 1989 | "``` py\n", 1990 | "Python 3: d = dict(zip(names, colors))\n", 1991 | "\n", 1992 | "\n", 1993 | "\n", 1994 | "```\n", 1995 | "用字典计数\n", 1996 | "\n", 1997 | "\n", 1998 | "\n", 1999 | "``` py\n", 2000 | "colors = ['red', 'green', 'red', 'blue', 'green', 'red']\n", 2001 | "\n", 2002 | "\n", 2003 | "\n", 2004 | "```\n", 2005 | "# 简单,基本的计数方法。适合初学者起步时学习。\n", 2006 | "\n", 2007 | "``` py\n", 2008 | "d = {}\n", 2009 | "\n", 2010 | "for color in colors:\n", 2011 | "\n", 2012 | " if color not in d:\n", 2013 | "\n", 2014 | " d[color] = 0\n", 2015 | "\n", 2016 | " d[color] += 1\n", 2017 | "\n", 2018 | "\n", 2019 | "\n", 2020 | "```\n", 2021 | "# {'blue': 1, 'green': 2, 'red': 3}\n", 2022 | "\n", 2023 | "\n", 2024 | "\n", 2025 | "更好的方法\n", 2026 | "\n", 2027 | "\n", 2028 | "\n", 2029 | "``` py\n", 2030 | "d = {}\n", 2031 | "\n", 2032 | "for color in colors:\n", 2033 | "\n", 2034 | " d[color] = d.get(color, 0) + 1\n", 2035 | "\n", 2036 | "\n", 2037 | "\n", 2038 | "```\n", 2039 | "# 稍微潮点的方法,但有些坑需要注意,适合熟练的老手。\n", 2040 | "\n", 2041 | "``` py\n", 2042 | "d = defaultdict(int)\n", 2043 | "\n", 2044 | "for color in colors:\n", 2045 | "\n", 2046 | " d[color] += 1\n", 2047 | "\n", 2048 | "\n", 2049 | "\n", 2050 | "```\n", 2051 | "用字典分组 — 第I部分和第II部分\n", 2052 | "\n", 2053 | "\n", 2054 | "\n", 2055 | "``` py\n", 2056 | "names = ['raymond', 'rachel', 'matthew', 'roger',\n", 2057 | "\n", 2058 | " 'betty', 'melissa', 'judith', 'charlie']\n", 2059 | "\n", 2060 | "\n", 2061 | "\n", 2062 | "```\n", 2063 | "# 在这个例子,我们按name的长度分组\n", 2064 | "\n", 2065 | "``` py\n", 2066 | "d = {}\n", 2067 | "\n", 2068 | "for name in names:\n", 2069 | "\n", 2070 | " key = len(name)\n", 2071 | "\n", 2072 | " if key not in d:\n", 2073 | "\n", 2074 | " d[key] = []\n", 2075 | "\n", 2076 | " d[key].append(name)\n", 2077 | "\n", 2078 | "\n", 2079 | "\n", 2080 | "```\n", 2081 | "# {5: ['roger', 'betty'], 6: ['rachel', 'judith'], 7: ['raymond', 'matthew',\n", 2082 | "\n", 2083 | "``` py\n", 2084 | "'melissa', 'charlie']}\n", 2085 | "\n", 2086 | "\n", 2087 | "\n", 2088 | "d = {}\n", 2089 | "\n", 2090 | "for name in names:\n", 2091 | "\n", 2092 | " key = len(name)\n", 2093 | "\n", 2094 | " d.setdefault(key, []).append(name)\n", 2095 | "\n", 2096 | "\n", 2097 | "\n", 2098 | "```\n", 2099 | "更好的方法\n", 2100 | "\n", 2101 | "\n", 2102 | "\n", 2103 | "``` py\n", 2104 | "d = defaultdict(list)\n", 2105 | "\n", 2106 | "for name in names:\n", 2107 | "\n", 2108 | " key = len(name)\n", 2109 | "\n", 2110 | " d[key].append(name)\n", 2111 | "\n", 2112 | "\n", 2113 | "\n", 2114 | "```\n", 2115 | "字典的popitem()是原子的吗?\n", 2116 | "\n", 2117 | "\n", 2118 | "\n", 2119 | "``` py\n", 2120 | "d = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}\n", 2121 | "\n", 2122 | "\n", 2123 | "\n", 2124 | "while d:\n", 2125 | "\n", 2126 | " key, value = d.popitem()\n", 2127 | "\n", 2128 | " print key, '-->', value\n", 2129 | "\n", 2130 | "\n", 2131 | "\n", 2132 | "```\n", 2133 | "popitem是原子的,所以多线程的时候没必要用锁包着它。\n", 2134 | "\n", 2135 | "\n", 2136 | "\n", 2137 | "连接字典\n", 2138 | "\n", 2139 | "\n", 2140 | "\n", 2141 | "``` py\n", 2142 | "defaults = {'color': 'red', 'user': 'guest'}\n", 2143 | "\n", 2144 | "parser = argparse.ArgumentParser()\n", 2145 | "\n", 2146 | "parser.add_argument('-u', '--user')\n", 2147 | "\n", 2148 | "parser.add_argument('-c', '--color')\n", 2149 | "\n", 2150 | "namespace = parser.parse_args([])\n", 2151 | "\n", 2152 | "command_line_args = {k: v for k, v in vars(namespace).items() if v}\n", 2153 | "\n", 2154 | "\n", 2155 | "\n", 2156 | "```\n", 2157 | "# 下面是通常的作法,默认使用第一个字典,接着用环境变量覆盖它,最后用命令行参数覆盖它。\n", 2158 | "\n", 2159 | "# 然而不幸的是,这种方法拷贝数据太疯狂。\n", 2160 | "\n", 2161 | "``` py\n", 2162 | "d = defaults.copy()\n", 2163 | "\n", 2164 | "d.update(os.environ)\n", 2165 | "\n", 2166 | "d.update(command_line_args)\n", 2167 | "\n", 2168 | "\n", 2169 | "\n", 2170 | "```\n", 2171 | "更好的方法\n", 2172 | "\n", 2173 | "\n", 2174 | "\n", 2175 | "``` py\n", 2176 | "d = ChainMap(command_line_args, os.environ, defaults)\n", 2177 | "\n", 2178 | "\n", 2179 | "\n", 2180 | "```\n", 2181 | "ChainMap在Python 3中加入。高效而优雅。\n", 2182 | "\n", 2183 | "\n", 2184 | "\n", 2185 | "提高可读性\n", 2186 | "\n", 2187 | "\n", 2188 | "\n", 2189 | "位置参数和下标很漂亮\n", 2190 | "\n", 2191 | "但关键字和名称更好\n", 2192 | "\n", 2193 | "第一种方法对计算机来说很便利\n", 2194 | "\n", 2195 | "第二种方法和人类思考方式一致\n", 2196 | "\n", 2197 | "\n", 2198 | "\n", 2199 | "用关键字参数提高函数调用的可读性\n", 2200 | "\n", 2201 | "\n", 2202 | "\n", 2203 | "``` py\n", 2204 | "twitter_search('@obama', False, 20, True)\n", 2205 | "\n", 2206 | "\n", 2207 | "\n", 2208 | "```\n", 2209 | "更好的方法\n", 2210 | "\n", 2211 | "\n", 2212 | "\n", 2213 | "``` py\n", 2214 | "twitter_search('@obama', retweets=False, numtweets=20, popular=True)\n", 2215 | "\n", 2216 | "\n", 2217 | "\n", 2218 | "```\n", 2219 | "第二种方法稍微(微秒级)慢一点,但为了代码的可读性和开发时间,值得。\n", 2220 | "\n", 2221 | "\n", 2222 | "\n", 2223 | "用namedtuple提高多个返回值的可读性\n", 2224 | "\n", 2225 | "\n", 2226 | "\n", 2227 | "# 老的testmod返回值\n", 2228 | "\n", 2229 | "``` py\n", 2230 | "doctest.testmod()\n", 2231 | "\n", 2232 | "```\n", 2233 | "# (0, 4)\n", 2234 | "\n", 2235 | "# 测试结果是好是坏?你看不出来,因为返回值不清晰。\n", 2236 | "\n", 2237 | "\n", 2238 | "\n", 2239 | "更好的方法\n", 2240 | "\n", 2241 | "\n", 2242 | "\n", 2243 | "# 新的testmod返回值, 一个namedtuple\n", 2244 | "\n", 2245 | "``` py\n", 2246 | "doctest.testmod()\n", 2247 | "\n", 2248 | "```\n", 2249 | "# TestResults(failed=0, attempted=4)\n", 2250 | "\n", 2251 | "\n", 2252 | "\n", 2253 | "namedtuple是tuple的子类,所以仍适用正常的元组操作,但它更友好。\n", 2254 | "\n", 2255 | "\n", 2256 | "\n", 2257 | "创建一个nametuple\n", 2258 | "\n", 2259 | "\n", 2260 | "\n", 2261 | "``` py\n", 2262 | "TestResults = namedTuple('TestResults', ['failed', 'attempted'])\n", 2263 | "\n", 2264 | "\n", 2265 | "\n", 2266 | "```\n", 2267 | "unpack序列\n", 2268 | "\n", 2269 | "\n", 2270 | "\n", 2271 | "``` py\n", 2272 | "p = 'Raymond', 'Hettinger', 0x30, 'python@example.com'\n", 2273 | "\n", 2274 | "\n", 2275 | "\n", 2276 | "```\n", 2277 | "# 其它语言的常用方法/习惯\n", 2278 | "\n", 2279 | "``` py\n", 2280 | "fname = p[0]\n", 2281 | "\n", 2282 | "lname = p[1]\n", 2283 | "\n", 2284 | "age = p[2]\n", 2285 | "\n", 2286 | "email = p[3]\n", 2287 | "\n", 2288 | "\n", 2289 | "\n", 2290 | "```\n", 2291 | "更好的方法\n", 2292 | "\n", 2293 | "\n", 2294 | "\n", 2295 | "``` py\n", 2296 | "fname, lname, age, email = p\n", 2297 | "\n", 2298 | "\n", 2299 | "\n", 2300 | "```\n", 2301 | "第二种方法用了unpack元组,更快,可读性更好。\n", 2302 | "\n", 2303 | "\n", 2304 | "\n", 2305 | "更新多个变量的状态\n", 2306 | "\n", 2307 | "\n", 2308 | "\n", 2309 | "``` py\n", 2310 | "def fibonacci(n):\n", 2311 | "\n", 2312 | " x = 0\n", 2313 | "\n", 2314 | " y = 1\n", 2315 | "\n", 2316 | " for i in range(n):\n", 2317 | "\n", 2318 | " print x\n", 2319 | "\n", 2320 | " t = y\n", 2321 | "\n", 2322 | " y = x + y\n", 2323 | "\n", 2324 | " x = t\n", 2325 | "\n", 2326 | "\n", 2327 | "\n", 2328 | "```\n", 2329 | "更好的方法\n", 2330 | "\n", 2331 | "\n", 2332 | "\n", 2333 | "``` py\n", 2334 | "def fibonacci(n):\n", 2335 | "\n", 2336 | " x, y = 0, 1\n", 2337 | "\n", 2338 | " for i in range(n):\n", 2339 | "\n", 2340 | " print x\n", 2341 | "\n", 2342 | " x, y = y, x + y\n", 2343 | "\n", 2344 | "\n", 2345 | "\n", 2346 | "```\n", 2347 | "第一种方法的问题\n", 2348 | "\n", 2349 | "\n", 2350 | "\n", 2351 | "x和y是状态,状态应该在一次操作中更新,分几行的话状态会互相对不上,这经常是bug的源头。\n", 2352 | "\n", 2353 | "操作有顺序要求\n", 2354 | "\n", 2355 | "太底层太细节\n", 2356 | "\n", 2357 | "\n", 2358 | "\n", 2359 | "第二种方法抽象层级更高,没有操作顺序出错的风险而且更效率更高。\n", 2360 | "\n", 2361 | "\n", 2362 | "\n", 2363 | "同时状态更新\n", 2364 | "\n", 2365 | "\n", 2366 | "\n", 2367 | "``` py\n", 2368 | "tmp_x = x + dx * t\n", 2369 | "\n", 2370 | "tmp_y = y + dy * t\n", 2371 | "\n", 2372 | "tmp_dx = influence(m, x, y, dx, dy, partial='x')\n", 2373 | "\n", 2374 | "tmp_dy = influence(m, x, y, dx, dy, partial='y')\n", 2375 | "\n", 2376 | "x = tmp_x\n", 2377 | "\n", 2378 | "y = tmp_y\n", 2379 | "\n", 2380 | "dx = tmp_dx\n", 2381 | "\n", 2382 | "dy = tmp_dy\n", 2383 | "\n", 2384 | "\n", 2385 | "\n", 2386 | "```\n", 2387 | "更好的方法\n", 2388 | "\n", 2389 | "\n", 2390 | "\n", 2391 | "``` py\n", 2392 | "x, y, dx, dy = (x + dx * t,\n", 2393 | "\n", 2394 | " y + dy * t,\n", 2395 | "\n", 2396 | " influence(m, x, y, dx, dy, partial='x'),\n", 2397 | "\n", 2398 | " influence(m, x, y, dx, dy, partial='y'))\n", 2399 | "\n", 2400 | "\n", 2401 | "\n", 2402 | "```\n", 2403 | "效率\n", 2404 | "\n", 2405 | "\n", 2406 | "\n", 2407 | "优化的基本原则\n", 2408 | "\n", 2409 | "除非必要,别无故移动数据\n", 2410 | "\n", 2411 | "稍微注意一下用线性的操作取代O(n**2)的操作\n", 2412 | "\n", 2413 | "\n", 2414 | "\n", 2415 | "总的来说,不要无故移动数据\n", 2416 | "\n", 2417 | "\n", 2418 | "\n", 2419 | "连接字符串\n", 2420 | "\n", 2421 | "\n", 2422 | "\n", 2423 | "``` py\n", 2424 | "names = ['raymond', 'rachel', 'matthew', 'roger',\n", 2425 | "\n", 2426 | " 'betty', 'melissa', 'judith', 'charlie']\n", 2427 | "\n", 2428 | "\n", 2429 | "\n", 2430 | "s = names[0]\n", 2431 | "\n", 2432 | "for name in names[1:]:\n", 2433 | "\n", 2434 | " s += ', ' + name\n", 2435 | "\n", 2436 | "print s\n", 2437 | "\n", 2438 | "\n", 2439 | "\n", 2440 | "```\n", 2441 | "更好的方法\n", 2442 | "\n", 2443 | "\n", 2444 | "\n", 2445 | "``` py\n", 2446 | "print ', '.join(names)\n", 2447 | "\n", 2448 | "\n", 2449 | "\n", 2450 | "```\n", 2451 | "更新序列\n", 2452 | "\n", 2453 | "\n", 2454 | "\n", 2455 | "``` py\n", 2456 | "names = ['raymond', 'rachel', 'matthew', 'roger',\n", 2457 | "\n", 2458 | " 'betty', 'melissa', 'judith', 'charlie']\n", 2459 | "\n", 2460 | "\n", 2461 | "\n", 2462 | "del names[0]\n", 2463 | "\n", 2464 | "```\n", 2465 | "# 下面的代码标志着你用错了数据结构\n", 2466 | "\n", 2467 | "``` py\n", 2468 | "names.pop(0)\n", 2469 | "\n", 2470 | "names.insert(0, 'mark')\n", 2471 | "\n", 2472 | "\n", 2473 | "\n", 2474 | "```\n", 2475 | "更好的方法\n", 2476 | "\n", 2477 | "\n", 2478 | "\n", 2479 | "``` py\n", 2480 | "names = deque(['raymond', 'rachel', 'matthew', 'roger',\n", 2481 | "\n", 2482 | " 'betty', 'melissa', 'judith', 'charlie'])\n", 2483 | "\n", 2484 | "\n", 2485 | "\n", 2486 | "```\n", 2487 | "# 用deque更有效率\n", 2488 | "\n", 2489 | "``` py\n", 2490 | "del names[0]\n", 2491 | "\n", 2492 | "names.popleft()\n", 2493 | "\n", 2494 | "names.appendleft('mark')\n", 2495 | "\n", 2496 | "\n", 2497 | "\n", 2498 | "```\n", 2499 | "装饰器和上下文管理\n", 2500 | "\n", 2501 | "\n", 2502 | "\n", 2503 | "用于把业务和管理的逻辑分开\n", 2504 | "\n", 2505 | "分解代码和提高代码重用性的干净优雅的好工具\n", 2506 | "\n", 2507 | "起个好名字很关键\n", 2508 | "\n", 2509 | "记住蜘蛛侠的格言:能力越大,责任越大\n", 2510 | "\n", 2511 | "\n", 2512 | "\n", 2513 | "使用装饰器分离出管理逻辑\n", 2514 | "\n", 2515 | "\n", 2516 | "\n", 2517 | "# 混着业务和管理逻辑,无法重用\n", 2518 | "\n", 2519 | "``` py\n", 2520 | "def web_lookup(url, saved={}):\n", 2521 | "\n", 2522 | " if url in saved:\n", 2523 | "\n", 2524 | " return saved[url]\n", 2525 | "\n", 2526 | " page = urllib.urlopen(url).read()\n", 2527 | "\n", 2528 | " saved[url] = page\n", 2529 | "\n", 2530 | " return page\n", 2531 | "\n", 2532 | "\n", 2533 | "\n", 2534 | "```\n", 2535 | "更好的方法\n", 2536 | "\n", 2537 | "\n", 2538 | "\n", 2539 | "``` py\n", 2540 | "@cache\n", 2541 | "\n", 2542 | "def web_lookup(url):\n", 2543 | "\n", 2544 | " return urllib.urlopen(url).read()\n", 2545 | "\n", 2546 | "\n", 2547 | "\n", 2548 | "```\n", 2549 | "注意:Python 3.2开始加入了functools.lru_cache解决这个问题。\n", 2550 | "\n", 2551 | "\n", 2552 | "\n", 2553 | "分离临时上下文\n", 2554 | "\n", 2555 | "\n", 2556 | "\n", 2557 | "# 保存旧的,创建新的\n", 2558 | "\n", 2559 | "``` py\n", 2560 | "old_context = getcontext().copy()\n", 2561 | "\n", 2562 | "getcontext().prec = 50\n", 2563 | "\n", 2564 | "print Decimal(355) / Decimal(113)\n", 2565 | "\n", 2566 | "setcontext(old_context)\n", 2567 | "\n", 2568 | "\n", 2569 | "\n", 2570 | "```\n", 2571 | "更好的方法\n", 2572 | "\n", 2573 | "\n", 2574 | "\n", 2575 | "``` py\n", 2576 | "with localcontext(Context(prec=50)):\n", 2577 | "\n", 2578 | " print Decimal(355) / Decimal(113)\n", 2579 | "\n", 2580 | "\n", 2581 | "\n", 2582 | "```\n", 2583 | "译注:示例代码在使用标准库decimal,这个库已经实现好了localcontext。\n", 2584 | "\n", 2585 | "\n", 2586 | "\n", 2587 | "如何打开关闭文件\n", 2588 | "\n", 2589 | "\n", 2590 | "\n", 2591 | "``` py\n", 2592 | "f = open('data.txt')\n", 2593 | "\n", 2594 | "try:\n", 2595 | "\n", 2596 | " data = f.read()\n", 2597 | "\n", 2598 | "finally:\n", 2599 | "\n", 2600 | " f.close()\n", 2601 | "\n", 2602 | "\n", 2603 | "\n", 2604 | "```\n", 2605 | "更好的方法\n", 2606 | "\n", 2607 | "\n", 2608 | "\n", 2609 | "``` py\n", 2610 | "with open('data.txt') as f:\n", 2611 | "\n", 2612 | " data = f.read()\n", 2613 | "\n", 2614 | "\n", 2615 | "\n", 2616 | "```\n", 2617 | "如何使用锁\n", 2618 | "\n", 2619 | "\n", 2620 | "\n", 2621 | "# 创建锁\n", 2622 | "\n", 2623 | "``` py\n", 2624 | "lock = threading.Lock()\n", 2625 | "\n", 2626 | "\n", 2627 | "\n", 2628 | "```\n", 2629 | "# 使用锁的老方法\n", 2630 | "\n", 2631 | "``` py\n", 2632 | "lock.acquire()\n", 2633 | "\n", 2634 | "try:\n", 2635 | "\n", 2636 | " print 'Critical section 1'\n", 2637 | "\n", 2638 | " print 'Critical section 2'\n", 2639 | "\n", 2640 | "finally:\n", 2641 | "\n", 2642 | " lock.release()\n", 2643 | "\n", 2644 | "\n", 2645 | "\n", 2646 | "```\n", 2647 | "更好的方法\n", 2648 | "\n", 2649 | "\n", 2650 | "\n", 2651 | "# 使用锁的新方法\n", 2652 | "\n", 2653 | "``` py\n", 2654 | "with lock:\n", 2655 | "\n", 2656 | " print 'Critical section 1'\n", 2657 | "\n", 2658 | " print 'Critical section 2'\n", 2659 | "\n", 2660 | "\n", 2661 | "\n", 2662 | "```\n", 2663 | "分离出临时的上下文\n", 2664 | "\n", 2665 | "\n", 2666 | "\n", 2667 | "``` py\n", 2668 | "try:\n", 2669 | "\n", 2670 | " os.remove('somefile.tmp')\n", 2671 | "\n", 2672 | "except OSError:\n", 2673 | "\n", 2674 | " pass\n", 2675 | "\n", 2676 | "\n", 2677 | "\n", 2678 | "```\n", 2679 | "更好的方法\n", 2680 | "\n", 2681 | "\n", 2682 | "\n", 2683 | "``` py\n", 2684 | "with ignored(OSError):\n", 2685 | "\n", 2686 | " os.remove('somefile.tmp')\n", 2687 | "\n", 2688 | "\n", 2689 | "\n", 2690 | "```\n", 2691 | "ignored是Python 3.4加入的, 文档。\n", 2692 | "\n", 2693 | "\n", 2694 | "\n", 2695 | "注意:ignored 实际上在标准库叫suppress(译注:contextlib.supress).\n", 2696 | "\n", 2697 | "\n", 2698 | "\n", 2699 | "试试创建你自己的ignored上下文管理器。\n", 2700 | "\n", 2701 | "\n", 2702 | "\n", 2703 | "``` py\n", 2704 | "@contextmanager\n", 2705 | "\n", 2706 | "def ignored(*exceptions):\n", 2707 | "\n", 2708 | " try:\n", 2709 | "\n", 2710 | " yield\n", 2711 | "\n", 2712 | " except exceptions:\n", 2713 | "\n", 2714 | " pass\n", 2715 | "\n", 2716 | "\n", 2717 | "\n", 2718 | "```\n", 2719 | "把它放在你的工具目录,你也可以忽略异常\n", 2720 | "\n", 2721 | "\n", 2722 | "\n", 2723 | "译注:contextmanager在标准库contextlib中,通过装饰生成器函数,省去用__enter__和__exit__写上下文管理器。详情请看文档。\n", 2724 | "\n", 2725 | "\n", 2726 | "\n", 2727 | "分离临时上下文\n", 2728 | "\n", 2729 | "\n", 2730 | "\n", 2731 | "# 临时把标准输出重定向到一个文件,然后再恢复正常\n", 2732 | "\n", 2733 | "``` py\n", 2734 | "with open('help.txt', 'w') as f:\n", 2735 | "\n", 2736 | " oldstdout = sys.stdout\n", 2737 | "\n", 2738 | " sys.stdout = f\n", 2739 | "\n", 2740 | " try:\n", 2741 | "\n", 2742 | " help(pow)\n", 2743 | "\n", 2744 | " finally:\n", 2745 | "\n", 2746 | " sys.stdout = oldstdout\n", 2747 | "\n", 2748 | "\n", 2749 | "\n", 2750 | "```\n", 2751 | "更好的写法\n", 2752 | "\n", 2753 | "\n", 2754 | "\n", 2755 | "``` py\n", 2756 | "with open('help.txt', 'w') as f:\n", 2757 | "\n", 2758 | " with redirect_stdout(f):\n", 2759 | "\n", 2760 | " help(pow)\n", 2761 | "\n", 2762 | "\n", 2763 | "\n", 2764 | "```\n", 2765 | "redirect_stdout在Python 3.4加入(译注:contextlib.redirect_stdout), bug反馈。\n", 2766 | "\n", 2767 | "\n", 2768 | "\n", 2769 | "实现你自己的redirect_stdout上下文管理器。\n", 2770 | "\n", 2771 | "\n", 2772 | "\n", 2773 | "``` py\n", 2774 | "@contextmanager\n", 2775 | "\n", 2776 | "def redirect_stdout(fileobj):\n", 2777 | "\n", 2778 | " oldstdout = sys.stdout\n", 2779 | "\n", 2780 | " sys.stdout = fileobj\n", 2781 | "\n", 2782 | " try:\n", 2783 | "\n", 2784 | " yield fieldobj\n", 2785 | "\n", 2786 | " finally:\n", 2787 | "\n", 2788 | " sys.stdout = oldstdout\n", 2789 | "\n", 2790 | "\n", 2791 | "\n", 2792 | "```\n", 2793 | "简洁的单句表达\n", 2794 | "\n", 2795 | "\n", 2796 | "\n", 2797 | "两个冲突的原则:\n", 2798 | "\n", 2799 | "\n", 2800 | "\n", 2801 | "一行不要有太多逻辑\n", 2802 | "\n", 2803 | "不要把单一的想法拆分成多个部分\n", 2804 | "\n", 2805 | "\n", 2806 | "\n", 2807 | "Raymond的原则:\n", 2808 | "\n", 2809 | "\n", 2810 | "\n", 2811 | "一行代码的逻辑等价于一句自然语言\n", 2812 | "\n", 2813 | "\n", 2814 | "\n", 2815 | "列表解析和生成器\n", 2816 | "\n", 2817 | "\n", 2818 | "\n", 2819 | "``` py\n", 2820 | "result = []\n", 2821 | "\n", 2822 | "for i in range(10):\n", 2823 | "\n", 2824 | "s = i ** 2\n", 2825 | "\n", 2826 | " result.append(s)\n", 2827 | "\n", 2828 | "print sum(result)\n", 2829 | "\n", 2830 | "\n", 2831 | "\n", 2832 | "```\n", 2833 | "更好的方法\n", 2834 | "\n", 2835 | "\n", 2836 | "\n", 2837 | "``` py\n", 2838 | "print sum(i**2 for i in xrange(10))\n", 2839 | "\n", 2840 | "\n", 2841 | "\n", 2842 | "```\n", 2843 | "第一种方法说的是你在做什么,第二种方法说的是你想要什么。\n", 2844 | "\n" 2845 | ] 2846 | } 2847 | ], 2848 | "source": [ 2849 | "for i in match_value_s:\n", 2850 | " print(i)" 2851 | ] 2852 | }, 2853 | { 2854 | "cell_type": "code", 2855 | "execution_count": 11, 2856 | "metadata": { 2857 | "ExecuteTime": { 2858 | "end_time": "2017-09-26T12:40:00.613970Z", 2859 | "start_time": "2017-09-26T12:40:00.594390Z" 2860 | }, 2861 | "collapsed": false 2862 | }, 2863 | "outputs": [ 2864 | { 2865 | "data": { 2866 | "text/plain": [ 2867 | "['---\\n',\n", 2868 | " 'title: 让你的Python优雅\\n',\n", 2869 | " '``` py\\nthumbnail:\\n',\n", 2870 | " \"'http://tse2.mm.bing.net/th?id=OIP.HMoLaA0mOSlTzJRGppa0ZQEgEs&pid=15.1'\\n\",\n", 2871 | " 'date: 2017-09-16 09:28:28\\n',\n", 2872 | " 'tags: [python, ]\\n',\n", 2873 | " 'banner:\\n',\n", 2874 | " '```\\n---\\n',\n", 2875 | " '\\n',\n", 2876 | " '参考译文来自:www.lightxue.com/transforming-code-into-beautiful-idiomatic-python\\n',\n", 2877 | " '\\n',\n", 2878 | " '在Python社区文化的浇灌下,演化出了一种独特的代码风格,去指导如何正确地使用Python,这就是常说的pythonic。\\n',\n", 2879 | " '\\n',\n", 2880 | " 'Raymond Hettinger是Python核心开发者,本文提到的许多特性都是他开发的。同时他也是Python社区热忱的布道师,不遗余力地传授pythoni\\n',\n", 2881 | " 'c之道。这篇文章是网友Jeff Paine整理的他在2013年美国的PyCon的演讲的笔记。\\n',\n", 2882 | " '\\n',\n", 2883 | " '---\\n',\n", 2884 | " '\\n',\n", 2885 | " '可下载 jupyter\\n',\n", 2886 | " '点击下载\\n',\n", 2887 | " '\\n',\n", 2888 | " '以下正文\\n',\n", 2889 | " '\\n',\n", 2890 | " '---\\n',\n", 2891 | " '\\n',\n", 2892 | " '## 遍历一个范围内的数字\\n',\n", 2893 | " '\\n',\n", 2894 | " '``` py\\n',\n", 2895 | " 'for i in [0, 1, 2, 3, 4, 5]:\\n',\n", 2896 | " ' print i ** 2\\n',\n", 2897 | " ' \\n',\n", 2898 | " 'for i in range(6):\\n',\n", 2899 | " ' print i ** 2\\n',\n", 2900 | " '```\\n',\n", 2901 | " '\\n',\n", 2902 | " '更好的方法\\n',\n", 2903 | " '\\n',\n", 2904 | " '``` py\\n',\n", 2905 | " 'for i in xrange(6):\\n',\n", 2906 | " ' print i ** 2\\n',\n", 2907 | " '```\\n',\n", 2908 | " '\\n',\n", 2909 | " 'xrange会返回一个迭代器,用来一次\\n',\n", 2910 | " '遍历一个范围。这种方式会比range更省内存。xrange在Python 3中已经改名为range。\\n',\n", 2911 | " '\\n',\n", 2912 | " '## 遍历一个集合\\n',\n", 2913 | " '\\n',\n", 2914 | " '``` py\\n',\n", 2915 | " \"colors = ['red', 'green', 'blue', 'yellow']\\n\",\n", 2916 | " ' \\n',\n", 2917 | " 'for i in range(len(colors)):\\n',\n", 2918 | " ' print colors[i]\\n',\n", 2919 | " '```\\n',\n", 2920 | " '\\n',\n", 2921 | " '更好的方法\\n',\n", 2922 | " '\\n',\n", 2923 | " '``` py\\n',\n", 2924 | " 'for color in colors:\\n',\n", 2925 | " ' print color\\n',\n", 2926 | " '```\\n',\n", 2927 | " '\\n',\n", 2928 | " '## 反向遍历\\n',\n", 2929 | " '\\n',\n", 2930 | " '``` py\\n',\n", 2931 | " \"colors = ['red', 'green', 'blue', 'yellow']\\n\",\n", 2932 | " ' \\n',\n", 2933 | " 'for i in range(len(colors)-1, -1, -1):\\n',\n", 2934 | " ' print colors[i]\\n',\n", 2935 | " '```\\n',\n", 2936 | " '\\n',\n", 2937 | " '更好的方法\\n',\n", 2938 | " '\\n',\n", 2939 | " '``` py\\n',\n", 2940 | " 'for color in reversed(colors):\\n',\n", 2941 | " ' print color\\n',\n", 2942 | " '```\\n',\n", 2943 | " '\\n',\n", 2944 | " '\\n',\n", 2945 | " '\\n',\n", 2946 | " '## 遍历一个集合及其下标\\n',\n", 2947 | " '\\n',\n", 2948 | " '``` py\\n',\n", 2949 | " \"colors = ['red', 'green', 'blue', 'yellow']\\n\",\n", 2950 | " ' \\n',\n", 2951 | " 'for i in range(len(colors)):\\n',\n", 2952 | " \" print i, '--->', colors[i]\\n\",\n", 2953 | " '```\\n',\n", 2954 | " '\\n',\n", 2955 | " '更好的方法\\n',\n", 2956 | " '\\n',\n", 2957 | " '``` py\\n',\n", 2958 | " 'for i, color in enumerate(colors):\\n',\n", 2959 | " \" print i, '--->', color\\n\",\n", 2960 | " '```\\n',\n", 2961 | " '\\n',\n", 2962 | " '这种写法效率高,优雅,而且帮你省去亲自创建和自增下标。\\n',\n", 2963 | " '\\n',\n", 2964 | " '当你发现你在操作集合的下标时,你很有可能在做错事。\\n',\n", 2965 | " '\\n',\n", 2966 | " '\\n',\n", 2967 | " '## 遍历两个集合\\n',\n", 2968 | " '\\n',\n", 2969 | " \"``` py\\nnames = ['raymond', 'rachel', 'matthew']\\n\",\n", 2970 | " \"colors = ['red', 'green', 'blue', 'yellow']\\n\",\n", 2971 | " '\\n',\n", 2972 | " 'n = min(len(names), len(colors))\\n',\n", 2973 | " 'for i in range(n):\\n',\n", 2974 | " \" print names[i], '--->', colors[i]\\n\",\n", 2975 | " '\\n',\n", 2976 | " 'for name, color in zip(names, colors):\\n',\n", 2977 | " \" print name, '--->', color\\n\",\n", 2978 | " '\\n',\n", 2979 | " '```\\n更好的方法\\n',\n", 2980 | " '\\n',\n", 2981 | " '``` py\\nfor name, color in izip(names, colors):\\n',\n", 2982 | " \" print name, '--->', color\\n\",\n", 2983 | " '\\n',\n", 2984 | " '```\\nzip在内存中生成一个新的列表,需要更多的内存。izip比zip效率更高。\\n',\n", 2985 | " '\\n',\n", 2986 | " '注意:在Python 3中,izip改名为zip,并替换了原来的zip成为内置函数。\\n',\n", 2987 | " '\\n',\n", 2988 | " '有序地遍历\\n',\n", 2989 | " '\\n',\n", 2990 | " \"``` py\\ncolors = ['red', 'green', 'blue', 'yellow']\\n\",\n", 2991 | " '\\n',\n", 2992 | " '```\\n# 正序\\n',\n", 2993 | " '``` py\\nfor color in sorted(colors):\\n',\n", 2994 | " ' print colors\\n',\n", 2995 | " '\\n',\n", 2996 | " '```\\n# 倒序\\n',\n", 2997 | " '``` py\\nfor color in sorted(colors, reverse=True):\\n',\n", 2998 | " ' print colors\\n',\n", 2999 | " '\\n',\n", 3000 | " '```\\n自定义排序顺序\\n',\n", 3001 | " '\\n',\n", 3002 | " \"``` py\\ncolors = ['red', 'green', 'blue', 'yellow']\\n\",\n", 3003 | " '\\n',\n", 3004 | " 'def compare_length(c1, c2):\\n',\n", 3005 | " ' if len(c1) < len(c2): return -1\\n',\n", 3006 | " ' if len(c1) > len(c2): return 1\\n',\n", 3007 | " ' return 0\\n',\n", 3008 | " '\\n',\n", 3009 | " 'print sorted(colors, cmp=compare_length)\\n',\n", 3010 | " '\\n',\n", 3011 | " '```\\n更好的方法\\n',\n", 3012 | " '\\n',\n", 3013 | " '``` py\\nprint sorted(colors, key=len)\\n',\n", 3014 | " '\\n',\n", 3015 | " '```\\n第一种方法效率低而且写起来很不爽。另外,Python 3已经不支持比较函数了。\\n',\n", 3016 | " '\\n',\n", 3017 | " '调用一个函数直到遇到标记值\\n',\n", 3018 | " '\\n',\n", 3019 | " '``` py\\nblocks = []\\n',\n", 3020 | " 'while True:\\n',\n", 3021 | " ' block = f.read(32)\\n',\n", 3022 | " \" if block == '':\\n\",\n", 3023 | " ' break\\n',\n", 3024 | " ' blocks.append(block)\\n',\n", 3025 | " '\\n',\n", 3026 | " '```\\n更好的方法\\n',\n", 3027 | " '\\n',\n", 3028 | " '``` py\\nblocks = []\\n',\n", 3029 | " \"for block in iter(partial(f.read, 32), ''):\\n\",\n", 3030 | " ' blocks.append(block)\\n',\n", 3031 | " '\\n',\n", 3032 | " '```\\niter接受两个参数。第一个是你反复调用的函数,第二个是标记值。\\n',\n", 3033 | " '\\n',\n", 3034 | " '译注:这个例子里不太能看出来方法二的优势,甚至觉得partial让代码可读性更差了。方法二的优势在于iter的返回值是个迭代器,迭代器能用在各种地方,set,s\\n',\n", 3035 | " '``` py\\norted,min,max,heapq,sum……\\n',\n", 3036 | " '\\n',\n", 3037 | " '```\\n在循环内识别多个退出点\\n',\n", 3038 | " '\\n',\n", 3039 | " '``` py\\ndef find(seq, target):\\n',\n", 3040 | " ' found = False\\n',\n", 3041 | " ' for i, value in enumerate(seq):\\n',\n", 3042 | " ' if value == target:\\n',\n", 3043 | " ' found = True\\n',\n", 3044 | " ' break\\n',\n", 3045 | " ' if not found:\\n',\n", 3046 | " ' return -1\\n',\n", 3047 | " ' return i\\n',\n", 3048 | " '\\n',\n", 3049 | " '```\\n更好的方法\\n',\n", 3050 | " '\\n',\n", 3051 | " '``` py\\ndef find(seq, target):\\n',\n", 3052 | " ' for i, value in enumerate(seq):\\n',\n", 3053 | " ' if value == target:\\n',\n", 3054 | " ' break\\n',\n", 3055 | " ' else:\\n',\n", 3056 | " ' return -1\\n',\n", 3057 | " ' return i\\n',\n", 3058 | " '\\n',\n", 3059 | " '```\\nfor执行完所有的循环后就会执行else。\\n',\n", 3060 | " '\\n',\n", 3061 | " '译注:刚了解for-else语法时会困惑,什么情况下会执行到else里。有两种方法去理解else。传统的方法是把for看作if,当for后面的条件为False时\\n',\n", 3062 | " '执行else。其实条件为False时,就是for循环没被break出去,把所有循环都跑完的时候。所以另一种方法就是把else记成nobreak,当for没有被b\\n',\n", 3063 | " 'reak,那么循环结束时会进入到else。\\n',\n", 3064 | " '\\n',\n", 3065 | " '遍历字典的key\\n',\n", 3066 | " '\\n',\n", 3067 | " \"``` py\\nd = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}\\n\",\n", 3068 | " '\\n',\n", 3069 | " 'for k in d:\\n',\n", 3070 | " ' print k\\n',\n", 3071 | " '\\n',\n", 3072 | " 'for k in d.keys():\\n',\n", 3073 | " \" if k.startswith('r'):\\n\",\n", 3074 | " ' del d[k]\\n',\n", 3075 | " '\\n',\n", 3076 | " '```\\n什么时候应该使用第二种而不是第一种方法?当你需要修改字典的时候。\\n',\n", 3077 | " '\\n',\n", 3078 | " '如果你在迭代一个东西的时候修改它,那就是在冒天下之大不韪,接下来发生什么都活该。\\n',\n", 3079 | " '\\n',\n", 3080 | " 'd.keys()把字典里所有的key都复制到一个列表里。然后你就可以修改字典了。\\n',\n", 3081 | " '\\n',\n", 3082 | " '注意:如果在Python\\n',\n", 3083 | " '3里迭代一个字典你得显示地写:list(d.keys()),因为d.keys()返回的是一个“字典视图”(一个提供字典key的动态视图的迭代器)。详情请看文档。\\n',\n", 3084 | " '\\n',\n", 3085 | " '遍历一个字典的key和value\\n',\n", 3086 | " '\\n',\n", 3087 | " '# 并不快,每次必须要重新哈希并做一次查找\\n',\n", 3088 | " '``` py\\nfor k in d:\\n',\n", 3089 | " \" print k, '--->', d[k]\\n\",\n", 3090 | " '\\n',\n", 3091 | " '```\\n# 产生一个很大的列表\\n',\n", 3092 | " '``` py\\nfor k, v in d.items():\\n',\n", 3093 | " \" print k, '--->', v\\n\",\n", 3094 | " '\\n',\n", 3095 | " '```\\n更好的方法\\n',\n", 3096 | " '\\n',\n", 3097 | " '``` py\\nfor k, v in d.iteritems():\\n',\n", 3098 | " \" print k, '--->', v\\n\",\n", 3099 | " '\\n',\n", 3100 | " '```\\niteritems()更好是因为它返回了一个迭代器。\\n',\n", 3101 | " '\\n',\n", 3102 | " '注意:Python 3已经没有iteritems()了,items()的行为和iteritems()很接近。详情请看文档。\\n',\n", 3103 | " '\\n',\n", 3104 | " '用key-value对构建字典\\n',\n", 3105 | " '\\n',\n", 3106 | " \"``` py\\nnames = ['raymond', 'rachel', 'matthew']\\n\",\n", 3107 | " \"colors = ['red', 'green', 'blue']\\n\",\n", 3108 | " '\\n',\n", 3109 | " 'd = dict(izip(names, colors))\\n',\n", 3110 | " \"```\\n# {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}\\n\",\n", 3111 | " '\\n',\n", 3112 | " '``` py\\nPython 3: d = dict(zip(names, colors))\\n',\n", 3113 | " '\\n',\n", 3114 | " '```\\n用字典计数\\n',\n", 3115 | " '\\n',\n", 3116 | " \"``` py\\ncolors = ['red', 'green', 'red', 'blue', 'green', 'red']\\n\",\n", 3117 | " '\\n',\n", 3118 | " '```\\n# 简单,基本的计数方法。适合初学者起步时学习。\\n',\n", 3119 | " '``` py\\nd = {}\\n',\n", 3120 | " 'for color in colors:\\n',\n", 3121 | " ' if color not in d:\\n',\n", 3122 | " ' d[color] = 0\\n',\n", 3123 | " ' d[color] += 1\\n',\n", 3124 | " '\\n',\n", 3125 | " \"```\\n# {'blue': 1, 'green': 2, 'red': 3}\\n\",\n", 3126 | " '\\n',\n", 3127 | " '更好的方法\\n',\n", 3128 | " '\\n',\n", 3129 | " '``` py\\nd = {}\\n',\n", 3130 | " 'for color in colors:\\n',\n", 3131 | " ' d[color] = d.get(color, 0) + 1\\n',\n", 3132 | " '\\n',\n", 3133 | " '```\\n# 稍微潮点的方法,但有些坑需要注意,适合熟练的老手。\\n',\n", 3134 | " '``` py\\nd = defaultdict(int)\\n',\n", 3135 | " 'for color in colors:\\n',\n", 3136 | " ' d[color] += 1\\n',\n", 3137 | " '\\n',\n", 3138 | " '```\\n用字典分组 — 第I部分和第II部分\\n',\n", 3139 | " '\\n',\n", 3140 | " \"``` py\\nnames = ['raymond', 'rachel', 'matthew', 'roger',\\n\",\n", 3141 | " \" 'betty', 'melissa', 'judith', 'charlie']\\n\",\n", 3142 | " '\\n',\n", 3143 | " '```\\n# 在这个例子,我们按name的长度分组\\n',\n", 3144 | " '``` py\\nd = {}\\n',\n", 3145 | " 'for name in names:\\n',\n", 3146 | " ' key = len(name)\\n',\n", 3147 | " ' if key not in d:\\n',\n", 3148 | " ' d[key] = []\\n',\n", 3149 | " ' d[key].append(name)\\n',\n", 3150 | " '\\n',\n", 3151 | " \"```\\n# {5: ['roger', 'betty'], 6: ['rachel', 'judith'], 7: ['raymond', 'matthew',\\n\",\n", 3152 | " \"``` py\\n'melissa', 'charlie']}\\n\",\n", 3153 | " '\\n',\n", 3154 | " 'd = {}\\n',\n", 3155 | " 'for name in names:\\n',\n", 3156 | " ' key = len(name)\\n',\n", 3157 | " ' d.setdefault(key, []).append(name)\\n',\n", 3158 | " '\\n',\n", 3159 | " '```\\n更好的方法\\n',\n", 3160 | " '\\n',\n", 3161 | " '``` py\\nd = defaultdict(list)\\n',\n", 3162 | " 'for name in names:\\n',\n", 3163 | " ' key = len(name)\\n',\n", 3164 | " ' d[key].append(name)\\n',\n", 3165 | " '\\n',\n", 3166 | " '```\\n字典的popitem()是原子的吗?\\n',\n", 3167 | " '\\n',\n", 3168 | " \"``` py\\nd = {'matthew': 'blue', 'rachel': 'green', 'raymond': 'red'}\\n\",\n", 3169 | " '\\n',\n", 3170 | " 'while d:\\n',\n", 3171 | " ' key, value = d.popitem()\\n',\n", 3172 | " \" print key, '-->', value\\n\",\n", 3173 | " '\\n',\n", 3174 | " '```\\npopitem是原子的,所以多线程的时候没必要用锁包着它。\\n',\n", 3175 | " '\\n',\n", 3176 | " '连接字典\\n',\n", 3177 | " '\\n',\n", 3178 | " \"``` py\\ndefaults = {'color': 'red', 'user': 'guest'}\\n\",\n", 3179 | " 'parser = argparse.ArgumentParser()\\n',\n", 3180 | " \"parser.add_argument('-u', '--user')\\n\",\n", 3181 | " \"parser.add_argument('-c', '--color')\\n\",\n", 3182 | " 'namespace = parser.parse_args([])\\n',\n", 3183 | " 'command_line_args = {k: v for k, v in vars(namespace).items() if v}\\n',\n", 3184 | " '\\n',\n", 3185 | " '```\\n# 下面是通常的作法,默认使用第一个字典,接着用环境变量覆盖它,最后用命令行参数覆盖它。\\n',\n", 3186 | " '# 然而不幸的是,这种方法拷贝数据太疯狂。\\n',\n", 3187 | " '``` py\\nd = defaults.copy()\\n',\n", 3188 | " 'd.update(os.environ)\\n',\n", 3189 | " 'd.update(command_line_args)\\n',\n", 3190 | " '\\n',\n", 3191 | " '```\\n更好的方法\\n',\n", 3192 | " '\\n',\n", 3193 | " '``` py\\nd = ChainMap(command_line_args, os.environ, defaults)\\n',\n", 3194 | " '\\n',\n", 3195 | " '```\\nChainMap在Python 3中加入。高效而优雅。\\n',\n", 3196 | " '\\n',\n", 3197 | " '提高可读性\\n',\n", 3198 | " '\\n',\n", 3199 | " '位置参数和下标很漂亮\\n',\n", 3200 | " '但关键字和名称更好\\n',\n", 3201 | " '第一种方法对计算机来说很便利\\n',\n", 3202 | " '第二种方法和人类思考方式一致\\n',\n", 3203 | " '\\n',\n", 3204 | " '用关键字参数提高函数调用的可读性\\n',\n", 3205 | " '\\n',\n", 3206 | " \"``` py\\ntwitter_search('@obama', False, 20, True)\\n\",\n", 3207 | " '\\n',\n", 3208 | " '```\\n更好的方法\\n',\n", 3209 | " '\\n',\n", 3210 | " \"``` py\\ntwitter_search('@obama', retweets=False, numtweets=20, popular=True)\\n\",\n", 3211 | " '\\n',\n", 3212 | " '```\\n第二种方法稍微(微秒级)慢一点,但为了代码的可读性和开发时间,值得。\\n',\n", 3213 | " '\\n',\n", 3214 | " '用namedtuple提高多个返回值的可读性\\n',\n", 3215 | " '\\n',\n", 3216 | " '# 老的testmod返回值\\n',\n", 3217 | " '``` py\\ndoctest.testmod()\\n',\n", 3218 | " '```\\n# (0, 4)\\n',\n", 3219 | " '# 测试结果是好是坏?你看不出来,因为返回值不清晰。\\n',\n", 3220 | " '\\n',\n", 3221 | " '更好的方法\\n',\n", 3222 | " '\\n',\n", 3223 | " '# 新的testmod返回值, 一个namedtuple\\n',\n", 3224 | " '``` py\\ndoctest.testmod()\\n',\n", 3225 | " '```\\n# TestResults(failed=0, attempted=4)\\n',\n", 3226 | " '\\n',\n", 3227 | " 'namedtuple是tuple的子类,所以仍适用正常的元组操作,但它更友好。\\n',\n", 3228 | " '\\n',\n", 3229 | " '创建一个nametuple\\n',\n", 3230 | " '\\n',\n", 3231 | " \"``` py\\nTestResults = namedTuple('TestResults', ['failed', 'attempted'])\\n\",\n", 3232 | " '\\n',\n", 3233 | " '```\\nunpack序列\\n',\n", 3234 | " '\\n',\n", 3235 | " \"``` py\\np = 'Raymond', 'Hettinger', 0x30, 'python@example.com'\\n\",\n", 3236 | " '\\n',\n", 3237 | " '```\\n# 其它语言的常用方法/习惯\\n',\n", 3238 | " '``` py\\nfname = p[0]\\n',\n", 3239 | " 'lname = p[1]\\n',\n", 3240 | " 'age = p[2]\\n',\n", 3241 | " 'email = p[3]\\n',\n", 3242 | " '\\n',\n", 3243 | " '```\\n更好的方法\\n',\n", 3244 | " '\\n',\n", 3245 | " '``` py\\nfname, lname, age, email = p\\n',\n", 3246 | " '\\n',\n", 3247 | " '```\\n第二种方法用了unpack元组,更快,可读性更好。\\n',\n", 3248 | " '\\n',\n", 3249 | " '更新多个变量的状态\\n',\n", 3250 | " '\\n',\n", 3251 | " '``` py\\ndef fibonacci(n):\\n',\n", 3252 | " ' x = 0\\n',\n", 3253 | " ' y = 1\\n',\n", 3254 | " ' for i in range(n):\\n',\n", 3255 | " ' print x\\n',\n", 3256 | " ' t = y\\n',\n", 3257 | " ' y = x + y\\n',\n", 3258 | " ' x = t\\n',\n", 3259 | " '\\n',\n", 3260 | " '```\\n更好的方法\\n',\n", 3261 | " '\\n',\n", 3262 | " '``` py\\ndef fibonacci(n):\\n',\n", 3263 | " ' x, y = 0, 1\\n',\n", 3264 | " ' for i in range(n):\\n',\n", 3265 | " ' print x\\n',\n", 3266 | " ' x, y = y, x + y\\n',\n", 3267 | " '\\n',\n", 3268 | " '```\\n第一种方法的问题\\n',\n", 3269 | " '\\n',\n", 3270 | " 'x和y是状态,状态应该在一次操作中更新,分几行的话状态会互相对不上,这经常是bug的源头。\\n',\n", 3271 | " '操作有顺序要求\\n',\n", 3272 | " '太底层太细节\\n',\n", 3273 | " '\\n',\n", 3274 | " '第二种方法抽象层级更高,没有操作顺序出错的风险而且更效率更高。\\n',\n", 3275 | " '\\n',\n", 3276 | " '同时状态更新\\n',\n", 3277 | " '\\n',\n", 3278 | " '``` py\\ntmp_x = x + dx * t\\n',\n", 3279 | " 'tmp_y = y + dy * t\\n',\n", 3280 | " \"tmp_dx = influence(m, x, y, dx, dy, partial='x')\\n\",\n", 3281 | " \"tmp_dy = influence(m, x, y, dx, dy, partial='y')\\n\",\n", 3282 | " 'x = tmp_x\\n',\n", 3283 | " 'y = tmp_y\\n',\n", 3284 | " 'dx = tmp_dx\\n',\n", 3285 | " 'dy = tmp_dy\\n',\n", 3286 | " '\\n',\n", 3287 | " '```\\n更好的方法\\n',\n", 3288 | " '\\n',\n", 3289 | " '``` py\\nx, y, dx, dy = (x + dx * t,\\n',\n", 3290 | " ' y + dy * t,\\n',\n", 3291 | " \" influence(m, x, y, dx, dy, partial='x'),\\n\",\n", 3292 | " \" influence(m, x, y, dx, dy, partial='y'))\\n\",\n", 3293 | " '\\n',\n", 3294 | " '```\\n效率\\n',\n", 3295 | " '\\n',\n", 3296 | " '优化的基本原则\\n',\n", 3297 | " '除非必要,别无故移动数据\\n',\n", 3298 | " '稍微注意一下用线性的操作取代O(n**2)的操作\\n',\n", 3299 | " '\\n',\n", 3300 | " '总的来说,不要无故移动数据\\n',\n", 3301 | " '\\n',\n", 3302 | " '连接字符串\\n',\n", 3303 | " '\\n',\n", 3304 | " \"``` py\\nnames = ['raymond', 'rachel', 'matthew', 'roger',\\n\",\n", 3305 | " \" 'betty', 'melissa', 'judith', 'charlie']\\n\",\n", 3306 | " '\\n',\n", 3307 | " 's = names[0]\\n',\n", 3308 | " 'for name in names[1:]:\\n',\n", 3309 | " \" s += ', ' + name\\n\",\n", 3310 | " 'print s\\n',\n", 3311 | " '\\n',\n", 3312 | " '```\\n更好的方法\\n',\n", 3313 | " '\\n',\n", 3314 | " \"``` py\\nprint ', '.join(names)\\n\",\n", 3315 | " '\\n',\n", 3316 | " '```\\n更新序列\\n',\n", 3317 | " '\\n',\n", 3318 | " \"``` py\\nnames = ['raymond', 'rachel', 'matthew', 'roger',\\n\",\n", 3319 | " \" 'betty', 'melissa', 'judith', 'charlie']\\n\",\n", 3320 | " '\\n',\n", 3321 | " 'del names[0]\\n',\n", 3322 | " '```\\n# 下面的代码标志着你用错了数据结构\\n',\n", 3323 | " '``` py\\nnames.pop(0)\\n',\n", 3324 | " \"names.insert(0, 'mark')\\n\",\n", 3325 | " '\\n',\n", 3326 | " '```\\n更好的方法\\n',\n", 3327 | " '\\n',\n", 3328 | " \"``` py\\nnames = deque(['raymond', 'rachel', 'matthew', 'roger',\\n\",\n", 3329 | " \" 'betty', 'melissa', 'judith', 'charlie'])\\n\",\n", 3330 | " '\\n',\n", 3331 | " '```\\n# 用deque更有效率\\n',\n", 3332 | " '``` py\\ndel names[0]\\n',\n", 3333 | " 'names.popleft()\\n',\n", 3334 | " \"names.appendleft('mark')\\n\",\n", 3335 | " '\\n',\n", 3336 | " '```\\n装饰器和上下文管理\\n',\n", 3337 | " '\\n',\n", 3338 | " '用于把业务和管理的逻辑分开\\n',\n", 3339 | " '分解代码和提高代码重用性的干净优雅的好工具\\n',\n", 3340 | " '起个好名字很关键\\n',\n", 3341 | " '记住蜘蛛侠的格言:能力越大,责任越大\\n',\n", 3342 | " '\\n',\n", 3343 | " '使用装饰器分离出管理逻辑\\n',\n", 3344 | " '\\n',\n", 3345 | " '# 混着业务和管理逻辑,无法重用\\n',\n", 3346 | " '``` py\\ndef web_lookup(url, saved={}):\\n',\n", 3347 | " ' if url in saved:\\n',\n", 3348 | " ' return saved[url]\\n',\n", 3349 | " ' page = urllib.urlopen(url).read()\\n',\n", 3350 | " ' saved[url] = page\\n',\n", 3351 | " ' return page\\n',\n", 3352 | " '\\n',\n", 3353 | " '```\\n更好的方法\\n',\n", 3354 | " '\\n',\n", 3355 | " '``` py\\n@cache\\n',\n", 3356 | " 'def web_lookup(url):\\n',\n", 3357 | " ' return urllib.urlopen(url).read()\\n',\n", 3358 | " '\\n',\n", 3359 | " '```\\n注意:Python 3.2开始加入了functools.lru_cache解决这个问题。\\n',\n", 3360 | " '\\n',\n", 3361 | " '分离临时上下文\\n',\n", 3362 | " '\\n',\n", 3363 | " '# 保存旧的,创建新的\\n',\n", 3364 | " '``` py\\nold_context = getcontext().copy()\\n',\n", 3365 | " 'getcontext().prec = 50\\n',\n", 3366 | " 'print Decimal(355) / Decimal(113)\\n',\n", 3367 | " 'setcontext(old_context)\\n',\n", 3368 | " '\\n',\n", 3369 | " '```\\n更好的方法\\n',\n", 3370 | " '\\n',\n", 3371 | " '``` py\\nwith localcontext(Context(prec=50)):\\n',\n", 3372 | " ' print Decimal(355) / Decimal(113)\\n',\n", 3373 | " '\\n',\n", 3374 | " '```\\n译注:示例代码在使用标准库decimal,这个库已经实现好了localcontext。\\n',\n", 3375 | " '\\n',\n", 3376 | " '如何打开关闭文件\\n',\n", 3377 | " '\\n',\n", 3378 | " \"``` py\\nf = open('data.txt')\\n\",\n", 3379 | " 'try:\\n',\n", 3380 | " ' data = f.read()\\n',\n", 3381 | " 'finally:\\n',\n", 3382 | " ' f.close()\\n',\n", 3383 | " '\\n',\n", 3384 | " '```\\n更好的方法\\n',\n", 3385 | " '\\n',\n", 3386 | " \"``` py\\nwith open('data.txt') as f:\\n\",\n", 3387 | " ' data = f.read()\\n',\n", 3388 | " '\\n',\n", 3389 | " '```\\n如何使用锁\\n',\n", 3390 | " '\\n',\n", 3391 | " '# 创建锁\\n',\n", 3392 | " '``` py\\nlock = threading.Lock()\\n',\n", 3393 | " '\\n',\n", 3394 | " '```\\n# 使用锁的老方法\\n',\n", 3395 | " '``` py\\nlock.acquire()\\n',\n", 3396 | " 'try:\\n',\n", 3397 | " \" print 'Critical section 1'\\n\",\n", 3398 | " \" print 'Critical section 2'\\n\",\n", 3399 | " 'finally:\\n',\n", 3400 | " ' lock.release()\\n',\n", 3401 | " '\\n',\n", 3402 | " '```\\n更好的方法\\n',\n", 3403 | " '\\n',\n", 3404 | " '# 使用锁的新方法\\n',\n", 3405 | " '``` py\\nwith lock:\\n',\n", 3406 | " \" print 'Critical section 1'\\n\",\n", 3407 | " \" print 'Critical section 2'\\n\",\n", 3408 | " '\\n',\n", 3409 | " '```\\n分离出临时的上下文\\n',\n", 3410 | " '\\n',\n", 3411 | " '``` py\\ntry:\\n',\n", 3412 | " \" os.remove('somefile.tmp')\\n\",\n", 3413 | " 'except OSError:\\n',\n", 3414 | " ' pass\\n',\n", 3415 | " '\\n',\n", 3416 | " '```\\n更好的方法\\n',\n", 3417 | " '\\n',\n", 3418 | " '``` py\\nwith ignored(OSError):\\n',\n", 3419 | " \" os.remove('somefile.tmp')\\n\",\n", 3420 | " '\\n',\n", 3421 | " '```\\nignored是Python 3.4加入的, 文档。\\n',\n", 3422 | " '\\n',\n", 3423 | " '注意:ignored 实际上在标准库叫suppress(译注:contextlib.supress).\\n',\n", 3424 | " '\\n',\n", 3425 | " '试试创建你自己的ignored上下文管理器。\\n',\n", 3426 | " '\\n',\n", 3427 | " '``` py\\n@contextmanager\\n',\n", 3428 | " 'def ignored(*exceptions):\\n',\n", 3429 | " ' try:\\n',\n", 3430 | " ' yield\\n',\n", 3431 | " ' except exceptions:\\n',\n", 3432 | " ' pass\\n',\n", 3433 | " '\\n',\n", 3434 | " '```\\n把它放在你的工具目录,你也可以忽略异常\\n',\n", 3435 | " '\\n',\n", 3436 | " '译注:contextmanager在标准库contextlib中,通过装饰生成器函数,省去用__enter__和__exit__写上下文管理器。详情请看文档。\\n',\n", 3437 | " '\\n',\n", 3438 | " '分离临时上下文\\n',\n", 3439 | " '\\n',\n", 3440 | " '# 临时把标准输出重定向到一个文件,然后再恢复正常\\n',\n", 3441 | " \"``` py\\nwith open('help.txt', 'w') as f:\\n\",\n", 3442 | " ' oldstdout = sys.stdout\\n',\n", 3443 | " ' sys.stdout = f\\n',\n", 3444 | " ' try:\\n',\n", 3445 | " ' help(pow)\\n',\n", 3446 | " ' finally:\\n',\n", 3447 | " ' sys.stdout = oldstdout\\n',\n", 3448 | " '\\n',\n", 3449 | " '```\\n更好的写法\\n',\n", 3450 | " '\\n',\n", 3451 | " \"``` py\\nwith open('help.txt', 'w') as f:\\n\",\n", 3452 | " ' with redirect_stdout(f):\\n',\n", 3453 | " ' help(pow)\\n',\n", 3454 | " '\\n',\n", 3455 | " '```\\nredirect_stdout在Python 3.4加入(译注:contextlib.redirect_stdout), bug反馈。\\n',\n", 3456 | " '\\n',\n", 3457 | " '实现你自己的redirect_stdout上下文管理器。\\n',\n", 3458 | " '\\n',\n", 3459 | " '``` py\\n@contextmanager\\n',\n", 3460 | " 'def redirect_stdout(fileobj):\\n',\n", 3461 | " ' oldstdout = sys.stdout\\n',\n", 3462 | " ' sys.stdout = fileobj\\n',\n", 3463 | " ' try:\\n',\n", 3464 | " ' yield fieldobj\\n',\n", 3465 | " ' finally:\\n',\n", 3466 | " ' sys.stdout = oldstdout\\n',\n", 3467 | " '\\n',\n", 3468 | " '```\\n简洁的单句表达\\n',\n", 3469 | " '\\n',\n", 3470 | " '两个冲突的原则:\\n',\n", 3471 | " '\\n',\n", 3472 | " '一行不要有太多逻辑\\n',\n", 3473 | " '不要把单一的想法拆分成多个部分\\n',\n", 3474 | " '\\n',\n", 3475 | " 'Raymond的原则:\\n',\n", 3476 | " '\\n',\n", 3477 | " '一行代码的逻辑等价于一句自然语言\\n',\n", 3478 | " '\\n',\n", 3479 | " '列表解析和生成器\\n',\n", 3480 | " '\\n',\n", 3481 | " '``` py\\nresult = []\\n',\n", 3482 | " 'for i in range(10):\\n',\n", 3483 | " 's = i ** 2\\n',\n", 3484 | " ' result.append(s)\\n',\n", 3485 | " 'print sum(result)\\n',\n", 3486 | " '\\n',\n", 3487 | " '```\\n更好的方法\\n',\n", 3488 | " '\\n',\n", 3489 | " '``` py\\nprint sum(i**2 for i in xrange(10))\\n',\n", 3490 | " '\\n',\n", 3491 | " '```\\n第一种方法说的是你在做什么,第二种方法说的是你想要什么。\\n']" 3492 | ] 3493 | }, 3494 | "execution_count": 11, 3495 | "metadata": {}, 3496 | "output_type": "execute_result" 3497 | } 3498 | ], 3499 | "source": [ 3500 | "match_value_s" 3501 | ] 3502 | }, 3503 | { 3504 | "cell_type": "code", 3505 | "execution_count": 12, 3506 | "metadata": { 3507 | "ExecuteTime": { 3508 | "end_time": "2017-09-26T12:40:00.619299Z", 3509 | "start_time": "2017-09-26T12:40:00.615521Z" 3510 | }, 3511 | "collapsed": false 3512 | }, 3513 | "outputs": [], 3514 | "source": [ 3515 | "write_file = '../test_w.md'\n", 3516 | "\n", 3517 | "file = open(write_file, 'w+')\n" 3518 | ] 3519 | }, 3520 | { 3521 | "cell_type": "code", 3522 | "execution_count": 13, 3523 | "metadata": { 3524 | "ExecuteTime": { 3525 | "end_time": "2017-09-26T12:40:00.631191Z", 3526 | "start_time": "2017-09-26T12:40:00.621121Z" 3527 | }, 3528 | "collapsed": false 3529 | }, 3530 | "outputs": [ 3531 | { 3532 | "name": "stdout", 3533 | "output_type": "stream", 3534 | "text": [ 3535 | "../test_w.md file is create markdown from ../让你的Python优雅.md\n" 3536 | ] 3537 | } 3538 | ], 3539 | "source": [ 3540 | "all = ''\n", 3541 | "for i in match_value_s:\n", 3542 | " file.write(i)\n", 3543 | "\n", 3544 | "file.close()\n", 3545 | "print('{} file is create markdown from {}'.format(write_file, Path))" 3546 | ] 3547 | }, 3548 | { 3549 | "cell_type": "markdown", 3550 | "metadata": {}, 3551 | "source": [ 3552 | "## 后记" 3553 | ] 3554 | }, 3555 | { 3556 | "cell_type": "code", 3557 | "execution_count": null, 3558 | "metadata": { 3559 | "collapsed": true 3560 | }, 3561 | "outputs": [], 3562 | "source": [] 3563 | } 3564 | ], 3565 | "metadata": { 3566 | "kernelspec": { 3567 | "display_name": "Python 3", 3568 | "language": "python", 3569 | "name": "python3" 3570 | }, 3571 | "language_info": { 3572 | "codemirror_mode": { 3573 | "name": "ipython", 3574 | "version": 3 3575 | }, 3576 | "file_extension": ".py", 3577 | "mimetype": "text/x-python", 3578 | "name": "python", 3579 | "nbconvert_exporter": "python", 3580 | "pygments_lexer": "ipython3", 3581 | "version": "3.6.0" 3582 | } 3583 | }, 3584 | "nbformat": 4, 3585 | "nbformat_minor": 2 3586 | } 3587 | --------------------------------------------------------------------------------