├── 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 | [](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 |
--------------------------------------------------------------------------------