├── .github
└── workflows
│ └── deploy.yml
├── .gitignore
├── Makefile
├── README.md
├── baidu_verify_code-akNcNpmYjb.html
├── exts
├── chinese_search.py
├── main.dic
├── smallseg.py
├── suffix.dic
└── zh.py
├── github-toc-maker-for-sphinx.py
├── make.bat
├── md2rst.py
├── pdf_maker.py
├── rebuild.sh
├── requirements.txt
├── source
├── _static
│ └── js
│ │ ├── baidutongji.js
│ │ └── readmore.js
├── _templates
│ └── versions.html
├── aboutme.rst
├── c01
│ ├── c01_01.md
│ ├── c01_01.rst
│ ├── c01_02.md
│ ├── c01_02.rst
│ ├── c01_03.md
│ ├── c01_03.rst
│ ├── c01_04.md
│ ├── c01_04.rst
│ ├── c01_05.md
│ ├── c01_05.rst
│ ├── c01_06.md
│ ├── c01_06.rst
│ ├── c01_07.md
│ ├── c01_07.rst
│ ├── c01_08.md
│ ├── c01_08.rst
│ ├── c01_09.md
│ ├── c01_09.rst
│ ├── c01_10.md
│ ├── c01_10.rst
│ ├── c01_11.md
│ ├── c01_11.rst
│ ├── c01_12.md
│ ├── c01_12.rst
│ ├── c01_13.md
│ ├── c01_13.rst
│ ├── c01_14.md
│ ├── c01_14.rst
│ ├── c01_15.md
│ ├── c01_15.rst
│ ├── c01_16.md
│ ├── c01_16.rst
│ ├── c01_17.md
│ ├── c01_17.rst
│ ├── c01_18.md
│ ├── c01_18.rst
│ ├── c01_19.md
│ ├── c01_19.rst
│ ├── c01_20.md
│ ├── c01_20.rst
│ ├── c01_21.md
│ ├── c01_21.rst
│ ├── c01_22.md
│ ├── c01_22.rst
│ ├── c01_23.md
│ ├── c01_23.rst
│ ├── c01_24.md
│ ├── c01_24.rst
│ ├── c01_25.md
│ ├── c01_25.rst
│ ├── c01_26.md
│ ├── c01_26.rst
│ ├── c01_27.md
│ ├── c01_27.rst
│ ├── c01_28.md
│ ├── c01_28.rst
│ ├── c01_29.md
│ ├── c01_29.rst
│ ├── c01_30.md
│ ├── c01_30.rst
│ ├── c01_31.md
│ ├── c01_31.rst
│ ├── c01_32.md
│ └── c01_32.rst
├── c02
│ ├── c02_01.md
│ ├── c02_01.rst
│ ├── c02_02.md
│ ├── c02_02.rst
│ ├── c02_03.md
│ ├── c02_03.rst
│ ├── c02_04.md
│ ├── c02_04.rst
│ ├── c02_05.md
│ ├── c02_05.rst
│ ├── c02_06.md
│ ├── c02_06.rst
│ ├── c02_07.md
│ ├── c02_07.rst
│ ├── c02_08.md
│ ├── c02_08.rst
│ ├── c02_09.md
│ ├── c02_09.rst
│ ├── c02_10.md
│ ├── c02_10.rst
│ ├── c02_11.md
│ ├── c02_11.rst
│ ├── c02_12.md
│ ├── c02_12.rst
│ ├── c02_13.md
│ ├── c02_13.rst
│ ├── c02_14.md
│ ├── c02_14.rst
│ ├── c02_15.md
│ ├── c02_15.rst
│ ├── c02_16.md
│ ├── c02_16.rst
│ ├── c02_17.md
│ ├── c02_17.rst
│ ├── c02_18.md
│ ├── c02_18.rst
│ ├── c02_19.md
│ ├── c02_19.rst
│ ├── c02_20.md
│ ├── c02_20.rst
│ ├── c02_21.md
│ ├── c02_21.rst
│ ├── c02_22.md
│ ├── c02_22.rst
│ ├── c02_23.md
│ └── c02_23.rst
├── c03
│ ├── c03_01.md
│ ├── c03_01.rst
│ ├── c03_02.md
│ ├── c03_02.rst
│ ├── c03_03.md
│ ├── c03_03.rst
│ ├── c03_04.md
│ ├── c03_04.rst
│ ├── c03_05.md
│ ├── c03_05.rst
│ ├── c03_06.md
│ ├── c03_06.rst
│ ├── c03_07.md
│ ├── c03_07.rst
│ ├── c03_08.md
│ ├── c03_08.rst
│ ├── c03_09.md
│ ├── c03_09.rst
│ ├── c03_10.md
│ ├── c03_10.rst
│ ├── c03_11.md
│ ├── c03_11.rst
│ ├── c03_12.md
│ ├── c03_12.rst
│ ├── c03_13.md
│ └── c03_13.rst
├── c04
│ ├── c04_01.md
│ ├── c04_01.rst
│ ├── c04_02.md
│ ├── c04_02.rst
│ ├── c04_03.md
│ └── c04_03.rst
├── c05
│ ├── c05_01.md
│ ├── c05_01.rst
│ ├── c05_02.md
│ ├── c05_02.rst
│ ├── c05_03.md
│ ├── c05_03.rst
│ ├── c05_04.md
│ ├── c05_04.rst
│ ├── c05_05.md
│ ├── c05_05.rst
│ ├── c05_06.md
│ ├── c05_06.rst
│ ├── c05_07.md
│ ├── c05_07.rst
│ ├── c05_08.md
│ ├── c05_08.rst
│ ├── c05_09.md
│ ├── c05_09.rst
│ ├── c05_10.md
│ ├── c05_10.rst
│ ├── c05_11.md
│ ├── c05_11.rst
│ ├── c05_12.md
│ ├── c05_12.rst
│ ├── c05_13.md
│ ├── c05_13.rst
│ ├── c05_14.md
│ ├── c05_14.rst
│ ├── c05_15.md
│ ├── c05_15.rst
│ ├── c05_16.md
│ ├── c05_16.rst
│ ├── c05_17.md
│ ├── c05_17.rst
│ ├── c05_18.md
│ ├── c05_18.rst
│ ├── c05_19.md
│ ├── c05_19.rst
│ ├── c05_20.md
│ ├── c05_20.rst
│ ├── c05_21.md
│ ├── c05_21.rst
│ ├── c05_22.md
│ ├── c05_22.rst
│ ├── c05_23.md
│ ├── c05_23.rst
│ ├── c05_24.md
│ ├── c05_24.rst
│ ├── c05_25.md
│ ├── c05_25.rst
│ ├── c05_26.md
│ ├── c05_26.rst
│ ├── c05_27.md
│ ├── c05_27.rst
│ ├── c05_28.md
│ ├── c05_28.rst
│ ├── c05_29.md
│ ├── c05_29.rst
│ ├── c05_30.md
│ ├── c05_30.rst
│ ├── c05_31.md
│ ├── c05_31.rst
│ ├── c05_32.md
│ ├── c05_32.rst
│ ├── c05_33.md
│ └── c05_33.rst
├── c06
│ ├── c06_01.md
│ ├── c06_01.rst
│ ├── c06_02.md
│ ├── c06_02.rst
│ ├── c06_03.md
│ ├── c06_03.rst
│ ├── c06_04.md
│ ├── c06_04.rst
│ ├── c06_05.md
│ ├── c06_05.rst
│ ├── c06_06.md
│ ├── c06_06.rst
│ ├── c06_07.md
│ ├── c06_07.rst
│ ├── c06_08.md
│ ├── c06_08.rst
│ ├── c06_09.md
│ ├── c06_09.rst
│ ├── c06_10.md
│ ├── c06_10.rst
│ ├── c06_11.md
│ ├── c06_11.rst
│ ├── c06_12.md
│ └── c06_12.rst
├── c07
│ ├── c07_01.md
│ ├── c07_01.rst
│ ├── c07_02.md
│ ├── c07_02.rst
│ ├── c07_03.md
│ ├── c07_03.rst
│ ├── c07_04.md
│ ├── c07_04.rst
│ ├── c07_05.md
│ ├── c07_05.rst
│ ├── c07_06.md
│ ├── c07_06.rst
│ ├── c07_07.md
│ ├── c07_07.rst
│ ├── c07_08.md
│ ├── c07_08.rst
│ ├── c07_09.md
│ ├── c07_09.rst
│ ├── c07_10.md
│ ├── c07_10.rst
│ ├── c07_11.md
│ ├── c07_11.rst
│ ├── c07_12.md
│ ├── c07_12.rst
│ ├── c07_13.md
│ ├── c07_13.rst
│ ├── c07_14.md
│ ├── c07_14.rst
│ ├── c07_15.md
│ ├── c07_15.rst
│ ├── c07_16.md
│ └── c07_16.rst
├── chapters
│ ├── p01.rst
│ ├── p02.rst
│ ├── p03.rst
│ ├── p04.rst
│ ├── p05.rst
│ ├── p06.rst
│ └── p07.rst
├── conf.py
├── index.rst
├── preface.rst
├── roadmap.rst
└── robots.txt
└── usercustomize.py
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy site files
2 |
3 | on:
4 | push:
5 | branches:
6 | - master # 只在master上push触发部署
7 | paths-ignore: # 下列文件的变更不触发部署,可以自行添加
8 | - README.md
9 | - LICENSE
10 | - md2rst.py
11 | - source/conf.py
12 |
13 | jobs:
14 | deploy:
15 | runs-on: ubuntu-latest # 使用ubuntu系统镜像运行自动化脚本
16 |
17 | steps: # 自动化步骤
18 | - uses: actions/checkout@v2 # 第一步,下载代码仓库
19 |
20 | - name: Deploy to Server # 第二步,rsync推文件
21 | uses: AEnterprise/rsync-deploy@v1.0 # 使用别人包装好的步骤镜像
22 | env:
23 | DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }} # 引用配置,SSH私钥
24 | ARGS: -avz --delete --exclude='*.pyc' # rsync参数,排除.pyc文件
25 | SERVER_PORT: ${{ secrets.SSH_PORT }} # SSH端口
26 | FOLDER: ./ # 要推送的文件夹,路径相对于代码仓库的根目录
27 | SERVER_IP: ${{ secrets.SSH_HOST }} # 引用配置,服务器的host名(IP或者域名domain.com)
28 | USERNAME: ${{ secrets.SSH_USERNAME }} # 引用配置,服务器登录名
29 | SERVER_DESTINATION: ${{ secrets.WORK_HOME }} # 部署到目标文件夹
30 | - name: Restart server # 第三步,重新部署服务
31 | uses: appleboy/ssh-action@master
32 | env:
33 | WORK_HOME: ${{ secrets.WORK_HOME }}
34 | with:
35 | host: ${{ secrets.SSH_HOST }} # 下面三个配置与上一步类似
36 | username: ${{ secrets.SSH_USERNAME }}
37 | port: ${{ secrets.SSH_PORT }} # SSH端口
38 | key: ${{ secrets.DEPLOY_KEY }} # 私钥
39 | script: |
40 | cd $WORK_HOME
41 | ./rebuild.sh
42 | envs: WORK_HOME # 要传入 script 的环境变量
43 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea/
2 | *.pyc
3 | Pipfile
4 | test*
5 | build_bak
6 | build
7 |
--------------------------------------------------------------------------------
/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line, and also
5 | # from the environment for the first two.
6 | SPHINXOPTS ?=
7 | SPHINXBUILD ?= sphinx-build
8 | SOURCEDIR = source
9 | BUILDDIR = build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
--------------------------------------------------------------------------------
/baidu_verify_code-akNcNpmYjb.html:
--------------------------------------------------------------------------------
1 | 3a591fe8805732ea01993ca4769e52e7
--------------------------------------------------------------------------------
/exts/chinese_search.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | def setup(app):
4 | import sphinx.search as search
5 | import zh
6 | search.languages["zh_CN"] = zh.SearchChinese
--------------------------------------------------------------------------------
/exts/suffix.dic:
--------------------------------------------------------------------------------
1 | 和
2 | 是
3 | 了
4 | 中
5 | 有
6 | 都
7 | 的
8 | 来
9 | 在
10 | 次
11 | 还
12 | 但
13 | 为
14 | 里
15 | 用
16 | 外
17 | 上
18 | 下
19 | 就
20 | 以
21 | 去
22 | 即
23 | 丁
24 | 万
25 | 乔
26 | 余
27 | 候
28 | 傅
29 | 冯
30 | 刘
31 | 单
32 | 卢
33 | 史
34 | 叶
35 | 吕
36 | 吴
37 | 唐
38 | 夏
39 | 姚
40 | 姜
41 | 孔
42 | 孙
43 | 孟
44 | 宋
45 | 尹
46 | 崔
47 | 常
48 | 康
49 | 廖
50 | 张
51 | 彭
52 | 徐
53 | 戴
54 | 文
55 | 方
56 | 易
57 | 曹
58 | 曾
59 | 朱
60 | 李
61 | 杜
62 | 杨
63 | 林
64 | 梁
65 | 武
66 | 段
67 | 毛
68 | 江
69 | 汤
70 | 沈
71 | 潘
72 | 熊
73 | 王
74 | 田
75 | 白
76 | 石
77 | 秦
78 | 罗
79 | 肖
80 | 胡
81 | 苏
82 | 范
83 | 董
84 | 蒋
85 | 薛
86 | 袁
87 | 谢
88 | 谭
89 | 贾
90 | 赖
91 | 赵
92 | 邓
93 | 邱
94 | 邵
95 | 邹
96 | 郑
97 | 郝
98 | 郭
99 | 金
100 | 钟
101 | 钱
102 | 阎
103 | 陆
104 | 陈
105 | 雷
106 | 韩
107 | 顾
108 | 马
109 | 高
110 | 魏
111 | 黄
112 | 黎
113 | 龙
114 | 龚
--------------------------------------------------------------------------------
/exts/zh.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | from sphinx.search import SearchLanguage
3 | from smallseg import SEG
4 |
5 | class SearchChinese(SearchLanguage):
6 | lang = 'zh'
7 |
8 | def init(self, options):
9 | print("reading Chiniese dictionary")
10 | self.seg = SEG()
11 |
12 | def split(self, input):
13 | return self.seg.cut(input.encode("utf8"))
14 |
15 | def word_filter(self, stemmed_word):
16 | return len(stemmed_word) > 1
17 |
--------------------------------------------------------------------------------
/make.bat:
--------------------------------------------------------------------------------
1 | @ECHO OFF
2 |
3 | pushd %~dp0
4 |
5 | REM Command file for Sphinx documentation
6 |
7 | if "%SPHINXBUILD%" == "" (
8 | set SPHINXBUILD=sphinx-build
9 | )
10 | set SOURCEDIR=source
11 | set BUILDDIR=build
12 |
13 | if "%1" == "" goto help
14 |
15 | %SPHINXBUILD% >NUL 2>NUL
16 | if errorlevel 9009 (
17 | echo.
18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
19 | echo.installed, then set the SPHINXBUILD environment variable to point
20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you
21 | echo.may add the Sphinx directory to PATH.
22 | echo.
23 | echo.If you don't have Sphinx installed, grab it from
24 | echo.http://sphinx-doc.org/
25 | exit /b 1
26 | )
27 |
28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
29 | goto end
30 |
31 | :help
32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
33 |
34 | :end
35 | popd
36 |
--------------------------------------------------------------------------------
/pdf_maker.py:
--------------------------------------------------------------------------------
1 | #!/usr/local/bin/python3
2 |
3 | import os
4 | import glob
5 | import fileinput
6 | import linecache
7 | from functools import partial
8 |
9 | repo_dir = os.getcwd()
10 | source_dir = os.path.join(repo_dir, "source")
11 | all_md_path = os.path.join(repo_dir, "all_v3.0.md",)
12 |
13 | count = 0
14 |
15 | with open(all_md_path, "w") as all_md:
16 | write = partial(print, file=all_md, end="")
17 | os.chdir(source_dir)
18 |
19 | for c_no in sorted(glob.glob("c*")):
20 | if c_no == "chapters" or c_no == "conf.py":
21 | continue
22 |
23 | # 读取并记下章节名
24 | c_name = linecache.getline(os.path.join(source_dir, "chapters", f"{c_no.replace('c', 'p')}.rst"), 2)
25 | write(f"# {c_name}\n\n", file=all_md)
26 |
27 | # 读取每一节的内容
28 | all_md_file = sorted(glob.glob(f"{source_dir}/{c_no}/*.md"))
29 | for line in fileinput.input(all_md_file):
30 | if "20200804124133" in line or "20200607174235" in line:
31 | continue
32 |
33 | if fileinput.isfirstline():
34 | count += 1
35 | if count%5 == 0:
36 | write("", end="\n\n")
37 |
38 | if line.startswith("# "):
39 | line = line.replace("# ", "## ")
40 | elif line.startswith("## "):
41 | line = line.replace("## ", "### ")
42 | elif line.startswith("### "):
43 | line = line.replace("### ", "#### ")
44 | elif "gif" in line:
45 | line = line.replace("![]", "![该图为GIF,请前往 magic.iswbm.com 浏览]")
46 |
47 | write(line)
48 |
49 |
--------------------------------------------------------------------------------
/rebuild.sh:
--------------------------------------------------------------------------------
1 | cat << EOF >/usr/local/lib/python3.10/site-packages/sphinx_rtd_theme/comments.html
2 |
3 |
10 |
11 | EOF
12 |
13 | rm -rf build/ && sphinx-multiversion source build/html && cp -rf build/html/master/* build/html/
14 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | alabaster==0.7.12
2 | argh==0.26.2
3 | Babel==2.9.1
4 | certifi==2019.6.16
5 | chardet==3.0.4
6 | docutils==0.14
7 | imagesize==1.1.0
8 | Jinja2==2.11.3
9 | livereload==2.6.1
10 | MarkupSafe==1.1.1
11 | packaging==19.0
12 | pathtools==0.1.2
13 | port-for==0.3.1
14 | Pygments==2.7.4
15 | pyparsing==2.4.0
16 | pytz==2019.1
17 | PyYAML==6.0.1
18 | requests==2.32.3
19 | six==1.12.0
20 | snowballstemmer==1.9.0
21 | Sphinx==2.1.2
22 | sphinx-autobuild==0.7.1
23 | sphinx-rtd-theme==0.4.3
24 | sphinxcontrib-applehelp==1.0.1
25 | sphinxcontrib-devhelp==1.0.1
26 | sphinxcontrib-htmlhelp==1.0.2
27 | sphinxcontrib-jsmath==1.0.1
28 | sphinxcontrib-qthelp==1.0.2
29 | sphinxcontrib-serializinghtml==1.1.3
30 | tornado==6.0.3
31 | urllib3==2.2.2
32 | watchdog==0.9.0
33 | sphinxcontrib-disqus==1.1.0
34 | sphinxcontrib-applehelp==1.0.1
35 | sphinxcontrib-devhelp==1.0.1
36 | sphinxcontrib-htmlhelp==1.0.2
37 | sphinxcontrib-jsmath==1.0.1
38 | sphinxcontrib-qthelp==1.0.2
39 | sphinxcontrib-serializinghtml==1.1.3
40 | sphinx-sitemap==2.2.0
41 | sphinx-multiversion==0.2.4
42 |
--------------------------------------------------------------------------------
/source/_static/js/baidutongji.js:
--------------------------------------------------------------------------------
1 | var _hmt = _hmt || [];
2 | (function() {
3 | var hm = document.createElement("script");
4 | hm.src = "https://hm.baidu.com/hm.js?f15534298fc176a5524b6da87883f37f";
5 | var s = document.getElementsByTagName("script")[0];
6 | s.parentNode.insertBefore(hm, s);
7 | })();
8 |
--------------------------------------------------------------------------------
/source/_templates/versions.html:
--------------------------------------------------------------------------------
1 | {%- if current_version %}
2 |
3 |
4 | Other Versions
5 | v: {{ current_version.name }}
6 |
7 |
8 |
9 | {%- if versions.tags %}
10 |
11 | - Tags
12 | {%- for item in versions.tags %}
13 | - {{ item.name }}
14 | {%- endfor %}
15 |
16 | {%- endif %}
17 | {%- if versions.branches %}
18 |
19 | - Branches
20 | {%- for item in versions.branches %}
21 | - {{ item.name }}
22 | {%- endfor %}
23 |
24 | {%- endif %}
25 |
26 |
27 | {%- endif %}
28 |
--------------------------------------------------------------------------------
/source/aboutme.rst:
--------------------------------------------------------------------------------
1 | ==============
2 | 关于作者
3 | ==============
4 |
5 | * 姓名: 王炳明
6 | * 微信: stromwbm
7 | * 公众号: 《Python编程时光》&《Go编程时光》
8 | * Email: wongbingming@163.com
9 | * GitHub: https://github.com/iswbm
10 |
11 | --------------------------------------------
12 |
13 | .. image:: http://image.iswbm.com/20200607174235.png
14 |
15 |
--------------------------------------------------------------------------------
/source/c01/c01_01.md:
--------------------------------------------------------------------------------
1 | # 1.1 默默无闻的省略号很好用
2 |
3 | 
4 |
5 | 在Python中,一切皆对象,省略号也不例外。
6 |
7 | 在 Python 3 中你可以直接写 `...` 来得到它
8 |
9 | ```python
10 | >>> ...
11 | Ellipsis
12 | >>> type(...)
13 |
14 | ```
15 |
16 | 而在 Python 2 中没有`...` 这个语法,只能直接写Ellipsis来获取。
17 |
18 | ```python
19 | >>> Ellipsis
20 | Ellipsis
21 | >>> type(Ellipsis)
22 |
23 | >>>
24 | ```
25 |
26 | 它转为布尔值时为真
27 |
28 | ```python
29 | >>> bool(...)
30 | True
31 | ```
32 |
33 | 最后,这东西是一个单例。
34 |
35 | ```python
36 | >>> id(...)
37 | 4362672336
38 | >>> id(...)
39 | 4362672336
40 | ```
41 |
42 | 那这东西有啥用呢?
43 |
44 | 1. 它是 Numpy 的一个语法糖
45 | 2. 在 Python 3 中可以使用 ... 代替 pass
46 |
47 | ```shell
48 | $ cat demo.py
49 | def func01():
50 | ...
51 |
52 | def func02():
53 | pass
54 |
55 | func01()
56 | func02()
57 |
58 | print("ok")
59 |
60 | $ python3 demo.py
61 | ok
62 | ```
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/source/c01/c01_01.rst:
--------------------------------------------------------------------------------
1 | 1.1 默默无闻的省略号很好用
2 | ==========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在Python中,一切皆对象,省略号也不例外。
7 |
8 | 在 Python 3 中你可以直接写 ``...`` 来得到它
9 |
10 | .. code:: python
11 |
12 | >>> ...
13 | Ellipsis
14 | >>> type(...)
15 |
16 |
17 | 而在 Python 2 中没有\ ``...`` 这个语法,只能直接写Ellipsis来获取。
18 |
19 | .. code:: python
20 |
21 | >>> Ellipsis
22 | Ellipsis
23 | >>> type(Ellipsis)
24 |
25 | >>>
26 |
27 | 它转为布尔值时为真
28 |
29 | .. code:: python
30 |
31 | >>> bool(...)
32 | True
33 |
34 | 最后,这东西是一个单例。
35 |
36 | .. code:: python
37 |
38 | >>> id(...)
39 | 4362672336
40 | >>> id(...)
41 | 4362672336
42 |
43 | 那这东西有啥用呢?
44 |
45 | 1. 它是 Numpy 的一个语法糖
46 | 2. 在 Python 3 中可以使用 … 代替 pass
47 |
48 | .. code:: shell
49 |
50 | $ cat demo.py
51 | def func01():
52 | ...
53 |
54 | def func02():
55 | pass
56 |
57 | func01()
58 | func02()
59 |
60 | print("ok")
61 |
62 | $ python3 demo.py
63 | ok
64 |
--------------------------------------------------------------------------------
/source/c01/c01_02.md:
--------------------------------------------------------------------------------
1 | # 1.2 使用 end 来结束代码块
2 |
3 | 
4 |
5 | 有不少编程语言,循环、判断代码块需要用 end 标明结束,这样一定程度上会使代码逻辑更加清晰一点。
6 |
7 | 但是其实在 Python 这种严格缩进的语言里并没有必要这样做。
8 |
9 | 如果你真的想用,也不是没有办法,具体你看下面这个例子。
10 |
11 | ```python
12 | __builtins__.end = None
13 |
14 |
15 | def my_abs(x):
16 | if x > 0:
17 | return x
18 | else:
19 | return -x
20 | end
21 | end
22 |
23 | print(my_abs(10))
24 | print(my_abs(-10))
25 | ```
26 |
27 | 执行后,输出如下
28 |
29 | ```shell
30 | [root@localhost ~]$ python demo.py
31 | 10
32 | 10
33 | ```
34 |
35 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/source/c01/c01_02.rst:
--------------------------------------------------------------------------------
1 | 1.2 使用 end 来结束代码块
2 | =========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 有不少编程语言,循环、判断代码块需要用 end
7 | 标明结束,这样一定程度上会使代码逻辑更加清晰一点。
8 |
9 | 但是其实在 Python 这种严格缩进的语言里并没有必要这样做。
10 |
11 | 如果你真的想用,也不是没有办法,具体你看下面这个例子。
12 |
13 | .. code:: python
14 |
15 | __builtins__.end = None
16 |
17 |
18 | def my_abs(x):
19 | if x > 0:
20 | return x
21 | else:
22 | return -x
23 | end
24 | end
25 |
26 | print(my_abs(10))
27 | print(my_abs(-10))
28 |
29 | 执行后,输出如下
30 |
31 | .. code:: shell
32 |
33 | [root@localhost ~]$ python demo.py
34 | 10
35 | 10
36 |
--------------------------------------------------------------------------------
/source/c01/c01_03.md:
--------------------------------------------------------------------------------
1 | # 1.3 可直接运行的 zip 包
2 | 
3 |
4 | 我们可以经常看到有 Python 包,居然可以以 zip 包进行发布,并且可以不用解压直接使用。
5 |
6 | 这与大多数人的认识的 Python 包格式不一样,正常人认为 Python 包的格式要嘛 是 egg,要嘛是whl 格式。
7 |
8 | 那么这个zip 是如何制作的呢,请看下面的示例。
9 |
10 | ```shell
11 | [root@localhost ~]# ls -l demo
12 | total 8
13 | -rw-r--r-- 1 root root 30 May 8 19:27 calc.py
14 | -rw-r--r-- 1 root root 35 May 8 19:33 __main__.py
15 | [root@localhost ~]#
16 | [root@localhost ~]# cat demo/__main__.py
17 | import calc
18 |
19 | print(calc.add(2, 3))
20 | [root@localhost ~]#
21 | [root@localhost ~]# cat demo/calc.py
22 | def add(x, y):
23 | return x+y
24 | [root@localhost ~]#
25 | [root@localhost ~]# python -m zipfile -c demo.zip demo/*
26 | [root@localhost ~]#
27 | ```
28 |
29 | 制作完成后,我们可以执行用 python 去执行它
30 |
31 | ```shell
32 | [root@localhost ~]# python demo.zip
33 | 5
34 | [root@localhost ~]#
35 | ```
36 |
37 |
38 |
39 |
40 |
--------------------------------------------------------------------------------
/source/c01/c01_03.rst:
--------------------------------------------------------------------------------
1 | 1.3 可直接运行的 zip 包
2 | =======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 我们可以经常看到有 Python 包,居然可以以 zip
7 | 包进行发布,并且可以不用解压直接使用。
8 |
9 | 这与大多数人的认识的 Python 包格式不一样,正常人认为 Python 包的格式要嘛
10 | 是 egg,要嘛是whl 格式。
11 |
12 | 那么这个zip 是如何制作的呢,请看下面的示例。
13 |
14 | .. code:: shell
15 |
16 | [root@localhost ~]# ls -l demo
17 | total 8
18 | -rw-r--r-- 1 root root 30 May 8 19:27 calc.py
19 | -rw-r--r-- 1 root root 35 May 8 19:33 __main__.py
20 | [root@localhost ~]#
21 | [root@localhost ~]# cat demo/__main__.py
22 | import calc
23 |
24 | print(calc.add(2, 3))
25 | [root@localhost ~]#
26 | [root@localhost ~]# cat demo/calc.py
27 | def add(x, y):
28 | return x+y
29 | [root@localhost ~]#
30 | [root@localhost ~]# python -m zipfile -c demo.zip demo/*
31 | [root@localhost ~]#
32 |
33 | 制作完成后,我们可以执行用 python 去执行它
34 |
35 | .. code:: shell
36 |
37 | [root@localhost ~]# python demo.zip
38 | 5
39 | [root@localhost ~]#
40 |
--------------------------------------------------------------------------------
/source/c01/c01_04.md:
--------------------------------------------------------------------------------
1 | # 1.4 反斜杠的倔强: 不写最后
2 | 
3 |
4 | `\` 在 Python 中的用法主要有两种
5 |
6 | **1、在行尾时,用做续行符**
7 |
8 | ```python
9 | [root@localhost ~]$ cat demo.py
10 | print("hello "\
11 | "world")
12 | [root@localhost ~]$
13 | [root@localhost ~]$ python demo.py
14 | hello world
15 | ```
16 |
17 |
18 |
19 | **2、在字符串中,用做转义字符,可以将普通字符转化为有特殊含义的字符。**
20 |
21 | ```python
22 | >>> str1='\nhello' #换行
23 | >>> print(str1)
24 |
25 | hello
26 | >>> str2='\thello' #tab
27 | >>> print(str2)
28 | hello
29 | ```
30 |
31 | 但是如果你用单`\`结尾是会报语法错误的
32 |
33 | ```python
34 | >>> str3="\"
35 | File "", line 1
36 | str3="\"
37 | ^
38 | SyntaxError: EOL while scanning string literal
39 | ```
40 |
41 | 就算你指定它是个 raw 字符串,也不行。
42 |
43 | ```python
44 | >>> str3=r"\"
45 | File "", line 1
46 | str3=r"\"
47 | ^
48 | SyntaxError: EOL while scanning string literal
49 | ```
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/source/c01/c01_04.rst:
--------------------------------------------------------------------------------
1 | 1.4 反斜杠的倔强: 不写最后
2 | ==========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | ``\`` 在 Python 中的用法主要有两种
7 |
8 | **1、在行尾时,用做续行符**
9 |
10 | .. code:: python
11 |
12 | [root@localhost ~]$ cat demo.py
13 | print("hello "\
14 | "world")
15 | [root@localhost ~]$
16 | [root@localhost ~]$ python demo.py
17 | hello world
18 |
19 | **2、在字符串中,用做转义字符,可以将普通字符转化为有特殊含义的字符。**
20 |
21 | .. code:: python
22 |
23 | >>> str1='\nhello' #换行
24 | >>> print(str1)
25 |
26 | hello
27 | >>> str2='\thello' #tab
28 | >>> print(str2)
29 | hello
30 |
31 | 但是如果你用单\ ``\``\ 结尾是会报语法错误的
32 |
33 | .. code:: python
34 |
35 | >>> str3="\"
36 | File "", line 1
37 | str3="\"
38 | ^
39 | SyntaxError: EOL while scanning string literal
40 |
41 | 就算你指定它是个 raw 字符串,也不行。
42 |
43 | .. code:: python
44 |
45 | >>> str3=r"\"
46 | File "", line 1
47 | str3=r"\"
48 | ^
49 | SyntaxError: EOL while scanning string literal
50 |
--------------------------------------------------------------------------------
/source/c01/c01_05.md:
--------------------------------------------------------------------------------
1 | # 1.5 如何修改解释器提示符
2 | 
3 |
4 | 这个当做今天的一个小彩蛋吧。应该算是比较冷门的,估计知道的人很少了吧。
5 |
6 | 正常情况下,我们在 终端下 执行Python 命令是这样的。
7 |
8 | ```python
9 | >>> for i in range(2):
10 | ... print (i)
11 | ...
12 | 0
13 | 1
14 | ```
15 |
16 | 你是否想过 `>>>` 和 `...` 这两个提示符也是可以修改的呢?
17 |
18 | ```python
19 | >>> import sys
20 | >>> sys.ps1
21 | '>>> '
22 | >>> sys.ps2
23 | '... '
24 | >>>
25 | >>> sys.ps2 = '---------------- '
26 | >>> sys.ps1 = 'Python编程时光>>>'
27 | Python编程时光>>>for i in range(2):
28 | ---------------- print (i)
29 | ----------------
30 | 0
31 | 1
32 | ```
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/source/c01/c01_05.rst:
--------------------------------------------------------------------------------
1 | 1.5 如何修改解释器提示符
2 | ========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 这个当做今天的一个小彩蛋吧。应该算是比较冷门的,估计知道的人很少了吧。
7 |
8 | 正常情况下,我们在 终端下 执行Python 命令是这样的。
9 |
10 | .. code:: python
11 |
12 | >>> for i in range(2):
13 | ... print (i)
14 | ...
15 | 0
16 | 1
17 |
18 | 你是否想过 ``>>>`` 和 ``...`` 这两个提示符也是可以修改的呢?
19 |
20 | .. code:: python
21 |
22 | >>> import sys
23 | >>> sys.ps1
24 | '>>> '
25 | >>> sys.ps2
26 | '... '
27 | >>>
28 | >>> sys.ps2 = '---------------- '
29 | >>> sys.ps1 = 'Python编程时光>>>'
30 | Python编程时光>>>for i in range(2):
31 | ---------------- print (i)
32 | ----------------
33 | 0
34 | 1
35 |
--------------------------------------------------------------------------------
/source/c01/c01_06.md:
--------------------------------------------------------------------------------
1 | # 1.6 简洁而优雅的链式比较
2 | 
3 |
4 | 先给你看一个示例:
5 |
6 | ```python
7 | >>> False == False == True
8 | False
9 | ```
10 |
11 | 你知道这个表达式为什么会会返回 False 吗?
12 |
13 | 它的运行原理与下面这个类似,是不是有点头绪了:
14 |
15 | ```python
16 | if 80 < score <= 90:
17 | print("成绩良好")
18 | ```
19 |
20 | 如果你还是不明白,那我再给你整个第一个例子的等价写法。
21 |
22 | ```python
23 | >>> False == False and False == True
24 | False
25 | ```
26 |
27 | 这个用法叫做链式比较。
28 |
29 |
--------------------------------------------------------------------------------
/source/c01/c01_06.rst:
--------------------------------------------------------------------------------
1 | 1.6 简洁而优雅的链式比较
2 | ========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 先给你看一个示例:
7 |
8 | .. code:: python
9 |
10 | >>> False == False == True
11 | False
12 |
13 | 你知道这个表达式为什么会会返回 False 吗?
14 |
15 | 它的运行原理与下面这个类似,是不是有点头绪了:
16 |
17 | .. code:: python
18 |
19 | if 80 < score <= 90:
20 | print("成绩良好")
21 |
22 | 如果你还是不明白,那我再给你整个第一个例子的等价写法。
23 |
24 | .. code:: python
25 |
26 | >>> False == False and False == True
27 | False
28 |
29 | 这个用法叫做链式比较。
30 |
--------------------------------------------------------------------------------
/source/c01/c01_07.md:
--------------------------------------------------------------------------------
1 | # 1.7 and 和 or 的短路效应
2 | 
3 |
4 | and 和 or 是我们再熟悉不过的两个逻辑运算符,在 Python 也有它的妙用。
5 |
6 | - 当一个 **or 表达式**中所有值都为真,Python会选择第一个值
7 |
8 | - 当一个 **and 表达式** 所有值都为真,Python 会选择最后一个值。
9 |
10 | 示例如下:
11 |
12 | ```python
13 | >>>(2 or 3) * (5 and 6 and 7)
14 | 14 # 2*7
15 | ```
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/source/c01/c01_07.rst:
--------------------------------------------------------------------------------
1 | 1.7 and 和 or 的短路效应
2 | ========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | and 和 or 是我们再熟悉不过的两个逻辑运算符,在 Python 也有它的妙用。
7 |
8 | - 当一个 **or 表达式**\ 中所有值都为真,Python会选择第一个值
9 |
10 | - 当一个 **and 表达式** 所有值都为真,Python 会选择最后一个值。
11 |
12 | 示例如下:
13 |
14 | .. code:: python
15 |
16 | >>>(2 or 3) * (5 and 6 and 7)
17 | 14 # 2*7
18 |
--------------------------------------------------------------------------------
/source/c01/c01_08.md:
--------------------------------------------------------------------------------
1 | # 1.8 连接多个列表最极客的方式
2 | 
3 |
4 | ```python
5 | >>> a = [1,2]
6 | >>> b = [3,4]
7 | >>> c = [5,6]
8 | >>>
9 | >>> sum((a,b,c), [])
10 | [1, 2, 3, 4, 5, 6]
11 | ```
12 |
13 |
14 |
--------------------------------------------------------------------------------
/source/c01/c01_08.rst:
--------------------------------------------------------------------------------
1 | 1.8 连接多个列表最极客的方式
2 | ============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | .. code:: python
7 |
8 | >>> a = [1,2]
9 | >>> b = [3,4]
10 | >>> c = [5,6]
11 | >>>
12 | >>> sum((a,b,c), [])
13 | [1, 2, 3, 4, 5, 6]
14 |
--------------------------------------------------------------------------------
/source/c01/c01_09.md:
--------------------------------------------------------------------------------
1 | # 1.9 字典居然是可以排序的?
2 | 
3 |
4 | 在 Python 3.6 之前字典不可排序的思想,似乎已经根深蒂固。
5 |
6 | ```python
7 | # Python2.7.10
8 | >>> mydict = {str(i):i for i in range(5)}
9 | >>> mydict
10 | {'1': 1, '0': 0, '3': 3, '2': 2, '4': 4}
11 | ```
12 |
13 | 假如哪一天,有人跟你说字典也可以是有序的,不要惊讶,那确实是真的
14 |
15 | 在 Python3.6 + 中字典已经是有序的,并且效率相较之前的还有所提升,具体信息你可以去查询相关资料。
16 |
17 | ```python
18 | # Python3.6.7
19 | >>> mydict = {str(i):i for i in range(5)}
20 | >>> mydict
21 | {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4}
22 | ```
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/source/c01/c01_09.rst:
--------------------------------------------------------------------------------
1 | 1.9 字典居然是可以排序的?
2 | ==========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在 Python 3.6 之前字典不可排序的思想,似乎已经根深蒂固。
7 |
8 | .. code:: python
9 |
10 | # Python2.7.10
11 | >>> mydict = {str(i):i for i in range(5)}
12 | >>> mydict
13 | {'1': 1, '0': 0, '3': 3, '2': 2, '4': 4}
14 |
15 | 假如哪一天,有人跟你说字典也可以是有序的,不要惊讶,那确实是真的
16 |
17 | 在 Python3.6 +
18 | 中字典已经是有序的,并且效率相较之前的还有所提升,具体信息你可以去查询相关资料。
19 |
20 | .. code:: python
21 |
22 | # Python3.6.7
23 | >>> mydict = {str(i):i for i in range(5)}
24 | >>> mydict
25 | {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4}
26 |
--------------------------------------------------------------------------------
/source/c01/c01_10.md:
--------------------------------------------------------------------------------
1 | # 1.10 哪些情况下不需要续行符?
2 | 
3 |
4 | 在写代码时,为了代码的可读性,代码的排版是尤为重要的。
5 |
6 | 为了实现高可读性的代码,我们常常使用到的就是续行符 `\`。
7 |
8 | ```python
9 | >>> a = 'talk is cheap,'\
10 | ... 'show me the code.'
11 | >>>
12 | >>> print(a)
13 | talk is cheap,show me the code.
14 | ```
15 |
16 | 那有哪些情况下,是不需要写续行符的呢?
17 |
18 | 经过总结,在这些符号中间的代码换行可以省略掉续行符:`[]`,`()`,`{}`
19 |
20 | ```python
21 | >>> my_list=[1,2,3,
22 | ... 4,5,6]
23 |
24 | >>> my_tuple=(1,2,3,
25 | ... 4,5,6)
26 |
27 | >>> my_dict={"name": "MING",
28 | ... "gender": "male"}
29 | ```
30 |
31 | 另外还有,在多行文本注释中 `'''` ,续行符也是可以不写的。
32 |
33 | ```python
34 | >>> text = '''talk is cheap,
35 | ... show me code.'''
36 | >>>
37 | ```
38 |
39 | 但是这种写法回车会自动转化为 `\n`
40 |
41 | ```python
42 | >>> text = '''talk is cheap,
43 | ... show me code.'''
44 | >>> text
45 | 'talk is cheap,\nshow me code.'
46 | ```
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/source/c01/c01_10.rst:
--------------------------------------------------------------------------------
1 | 1.10 哪些情况下不需要续行符?
2 | =============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在写代码时,为了代码的可读性,代码的排版是尤为重要的。
7 |
8 | 为了实现高可读性的代码,我们常常使用到的就是续行符 ``\``\ 。
9 |
10 | .. code:: python
11 |
12 | >>> a = 'talk is cheap,'\
13 | ... 'show me the code.'
14 | >>>
15 | >>> print(a)
16 | talk is cheap,show me the code.
17 |
18 | 那有哪些情况下,是不需要写续行符的呢?
19 |
20 | 经过总结,在这些符号中间的代码换行可以省略掉续行符:\ ``[]``,\ ``()``,\ ``{}``
21 |
22 | .. code:: python
23 |
24 | >>> my_list=[1,2,3,
25 | ... 4,5,6]
26 |
27 | >>> my_tuple=(1,2,3,
28 | ... 4,5,6)
29 |
30 | >>> my_dict={"name": "MING",
31 | ... "gender": "male"}
32 |
33 | 另外还有,在多行文本注释中 ``'''`` ,续行符也是可以不写的。
34 |
35 | .. code:: python
36 |
37 | >>> text = '''talk is cheap,
38 | ... show me code.'''
39 | >>>
40 |
41 | 但是这种写法回车会自动转化为 ``\n``
42 |
43 | .. code:: python
44 |
45 | >>> text = '''talk is cheap,
46 | ... show me code.'''
47 | >>> text
48 | 'talk is cheap,\nshow me code.'
49 |
--------------------------------------------------------------------------------
/source/c01/c01_11.md:
--------------------------------------------------------------------------------
1 | # 1.11 用户无感知的小整数池
2 | 
3 |
4 | 为避免整数频繁申请和销毁内存空间,Python 定义了一个小整数池 [-5, 256] 这些整数对象是提前建立好的,不会被垃圾回收。
5 |
6 | 以下代码请在 终端Python环境下测试,如果你是在IDE中测试,由于 IDE 的影响,效果会有所不同。
7 |
8 | ```python
9 | >>> a = -6
10 | >>> b = -6
11 | >>> a is b
12 | False
13 |
14 | >>> a = 256
15 | >>> b = 256
16 | >>> a is b
17 | True
18 |
19 | >>> a = 257
20 | >>> b = 257
21 | >>> a is b
22 | False
23 |
24 | >>> a = 257; b = 257
25 | >>> a is b
26 | True
27 | ```
28 |
29 | **问题又来了:最后一个示例,为啥是True?**
30 |
31 | 因为当你在同一行里,同时给两个变量赋同一值时,解释器知道这个对象已经生成,那么它就会引用到同一个对象。如果分成两行的话,解释器并不知道这个对象已经存在了,就会重新申请内存存放这个对象。
32 |
33 |
34 |
--------------------------------------------------------------------------------
/source/c01/c01_11.rst:
--------------------------------------------------------------------------------
1 | 1.11 用户无感知的小整数池
2 | =========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 为避免整数频繁申请和销毁内存空间,Python 定义了一个小整数池 [-5, 256]
7 | 这些整数对象是提前建立好的,不会被垃圾回收。
8 |
9 | 以下代码请在 终端Python环境下测试,如果你是在IDE中测试,由于 IDE
10 | 的影响,效果会有所不同。
11 |
12 | .. code:: python
13 |
14 | >>> a = -6
15 | >>> b = -6
16 | >>> a is b
17 | False
18 |
19 | >>> a = 256
20 | >>> b = 256
21 | >>> a is b
22 | True
23 |
24 | >>> a = 257
25 | >>> b = 257
26 | >>> a is b
27 | False
28 |
29 | >>> a = 257; b = 257
30 | >>> a is b
31 | True
32 |
33 | **问题又来了:最后一个示例,为啥是True?**
34 |
35 | 因为当你在同一行里,同时给两个变量赋同一值时,解释器知道这个对象已经生成,那么它就会引用到同一个对象。如果分成两行的话,解释器并不知道这个对象已经存在了,就会重新申请内存存放这个对象。
36 |
--------------------------------------------------------------------------------
/source/c01/c01_12.md:
--------------------------------------------------------------------------------
1 | # 1.12 神奇的 intern 机制
2 | 
3 |
4 | 字符串类型作为Python中最常用的数据类型之一,Python解释器为了提高字符串使用的效率和使用性能,做了很多优化。
5 |
6 | 例如:Python解释器中使用了 intern(字符串驻留)的技术来提高字符串效率,什么是intern机制?就是同样的字符串对象仅仅会保存一份,放在一个字符串储蓄池中,是共用的,当然,肯定不能改变,这也决定了字符串必须是不可变对象。
7 |
8 | ```python
9 | >>> s1="hello"
10 | >>> s2="hello"
11 | >>> s1 is s2
12 | True
13 |
14 | # 如果有空格,默认不启用intern机制
15 | >>> s1="hell o"
16 | >>> s2="hell o"
17 | >>> s1 is s2
18 | False
19 |
20 | # 如果一个字符串长度超过20个字符,不启动intern机制
21 | >>> s1 = "a" * 20
22 | >>> s2 = "a" * 20
23 | >>> s1 is s2
24 | True
25 |
26 | >>> s1 = "a" * 21
27 | >>> s2 = "a" * 21
28 | >>> s1 is s2
29 | False
30 |
31 | >>> s1 = "ab" * 10
32 | >>> s2 = "ab" * 10
33 | >>> s1 is s2
34 | True
35 |
36 | >>> s1 = "ab" * 11
37 | >>> s2 = "ab" * 11
38 | >>> s1 is s2
39 | False
40 | ```
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/source/c01/c01_12.rst:
--------------------------------------------------------------------------------
1 | 1.12 神奇的 intern 机制
2 | =======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 字符串类型作为Python中最常用的数据类型之一,Python解释器为了提高字符串使用的效率和使用性能,做了很多优化。
7 |
8 | 例如:Python解释器中使用了
9 | intern(字符串驻留)的技术来提高字符串效率,什么是intern机制?就是同样的字符串对象仅仅会保存一份,放在一个字符串储蓄池中,是共用的,当然,肯定不能改变,这也决定了字符串必须是不可变对象。
10 |
11 | .. code:: python
12 |
13 | >>> s1="hello"
14 | >>> s2="hello"
15 | >>> s1 is s2
16 | True
17 |
18 | # 如果有空格,默认不启用intern机制
19 | >>> s1="hell o"
20 | >>> s2="hell o"
21 | >>> s1 is s2
22 | False
23 |
24 | # 如果一个字符串长度超过20个字符,不启动intern机制
25 | >>> s1 = "a" * 20
26 | >>> s2 = "a" * 20
27 | >>> s1 is s2
28 | True
29 |
30 | >>> s1 = "a" * 21
31 | >>> s2 = "a" * 21
32 | >>> s1 is s2
33 | False
34 |
35 | >>> s1 = "ab" * 10
36 | >>> s2 = "ab" * 10
37 | >>> s1 is s2
38 | True
39 |
40 | >>> s1 = "ab" * 11
41 | >>> s2 = "ab" * 11
42 | >>> s1 is s2
43 | False
44 |
--------------------------------------------------------------------------------
/source/c01/c01_13.md:
--------------------------------------------------------------------------------
1 | # 1.13 site-packages和 dist-packages
2 | 
3 |
4 | 如果你足够细心,你会在你的机器上,有些包是安装在 **site-packages** 下,而有些包安装在 **dist-packages** 下。
5 |
6 | **它们有什么区别呢?**
7 |
8 | 一般情况下,你只见过 site-packages 这个目录,而你所安装的包也将安装在 这个目录下。
9 |
10 | 而 dist-packages 其实是 debian 系的 Linux 系统(如 Ubuntu)才特有的目录,当你使用 apt 去安装的 Python 包会使用 dist-packages,而你使用 pip 或者 easy_install 安装的包还是照常安装在 site-packages 下。
11 |
12 | Debian 这么设计的原因,是为了减少不同来源的 Python 之间产生的冲突。
13 |
14 | 如何查找 Python 安装目录
15 |
16 | ```python
17 | >>> from distutils.sysconfig import get_python_lib
18 | >>> print(get_python_lib())
19 | /usr/lib/python2.7/site-packages
20 | ```
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/source/c01/c01_13.rst:
--------------------------------------------------------------------------------
1 | 1.13 site-packages和 dist-packages
2 | ==================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 如果你足够细心,你会在你的机器上,有些包是安装在 **site-packages**
7 | 下,而有些包安装在 **dist-packages** 下。
8 |
9 | **它们有什么区别呢?**
10 |
11 | 一般情况下,你只见过 site-packages 这个目录,而你所安装的包也将安装在
12 | 这个目录下。
13 |
14 | 而 dist-packages 其实是 debian 系的 Linux 系统(如
15 | Ubuntu)才特有的目录,当你使用 apt 去安装的 Python 包会使用
16 | dist-packages,而你使用 pip 或者 easy_install 安装的包还是照常安装在
17 | site-packages 下。
18 |
19 | Debian 这么设计的原因,是为了减少不同来源的 Python 之间产生的冲突。
20 |
21 | 如何查找 Python 安装目录
22 |
23 | .. code:: python
24 |
25 | >>> from distutils.sysconfig import get_python_lib
26 | >>> print(get_python_lib())
27 | /usr/lib/python2.7/site-packages
28 |
--------------------------------------------------------------------------------
/source/c01/c01_14.md:
--------------------------------------------------------------------------------
1 | # 1.14 argument 和 parameter 的区别?
2 | 
3 |
4 | arguments 和 parameter 的翻译都是参数,在中文场景下,二者混用基本没有问题,毕竟都叫参数嘛。
5 |
6 | 但若要严格再进行区分,它们实际上还有各自的叫法
7 |
8 | - parameter:形参(**formal parameter**),体现在函数内部,作用域是这个函数体。
9 | - argument :实参(**actual parameter**),调用函数实际传递的参数。
10 |
11 | 举个例子,如下这段代码,`"error"` 为 argument,而 msg 为 `parameter`。
12 |
13 | ```python
14 | def output_msg(msg):
15 | print(msg)
16 |
17 | output_msg("error")
18 | ```
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/source/c01/c01_14.rst:
--------------------------------------------------------------------------------
1 | 1.14 argument 和 parameter 的区别?
2 | ==================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | arguments 和 parameter
7 | 的翻译都是参数,在中文场景下,二者混用基本没有问题,毕竟都叫参数嘛。
8 |
9 | 但若要严格再进行区分,它们实际上还有各自的叫法
10 |
11 | - parameter:形参(\ **formal
12 | parameter**\ ),体现在函数内部,作用域是这个函数体。
13 | - argument :实参(\ **actual parameter**\ ),调用函数实际传递的参数。
14 |
15 | 举个例子,如下这段代码,\ ``"error"`` 为 argument,而 msg 为
16 | ``parameter``\ 。
17 |
18 | .. code:: python
19 |
20 | def output_msg(msg):
21 | print(msg)
22 |
23 | output_msg("error")
24 |
--------------------------------------------------------------------------------
/source/c01/c01_15.md:
--------------------------------------------------------------------------------
1 | # 1.15 /usr/bin/env python 有什么用?
2 | 
3 |
4 | 我们经常会在别人的脚本或者项目的入口文件里看到第一行是下面这样
5 |
6 | ```shell
7 | #!/usr/bin/python
8 | ```
9 |
10 | 或者这样
11 |
12 | ```shell
13 | #!/usr/bin/env python
14 | ```
15 |
16 | 这两者有什么区别呢?
17 |
18 | 稍微接触过 linux 的人都知道 `/usr/bin/python` 就是我们执行 `python` 进入console 模式里的 `python`
19 |
20 | 
21 |
22 | 而当你在可执行文件头里使用 `#!` + `/usr/bin/python` ,意思就是说你得用哪个软件 (python)来执行这个文件。
23 |
24 | 那么加和不加有什么区别呢?
25 |
26 | 不加的话,你每次执行这个脚本时,都得这样: `python xx.py` ,
27 |
28 | 
29 |
30 | 有没有一种方式?可以省去每次都加 `python` 呢?
31 |
32 | 当然有,你可以文件头里加上`#!/usr/bin/python` ,那么当这个文件有可执行权限 时,只直接写这个脚本文件,就像下面这样。
33 |
34 | 
35 |
36 | 明白了这个后,再来看看 `!/usr/bin/env python` 这个 又是什么意思 ?
37 |
38 | 当我执行 `env python` 时,自动进入了 python console 的模式。
39 |
40 | 
41 |
42 | 这是为什么?和 直接执行 python 好像没什么区别呀
43 |
44 | 当你执行 `env python` 时,它其实会去 `env | grep PATH` 里(也就是 /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin )这几个路径里去依次查找名为python的可执行文件。
45 |
46 | 找到一个就直接执行,上面我们的 python 路径是在 `/usr/bin/python` 里,在 `PATH` 列表里倒数第二个目录下,所以当我在 `/usr/local/sbin` 下创建一个名字也为 python 的可执行文件时,就会执行 `/usr/local/sbin/python` 了。
47 |
48 | 具体演示过程,你可以看下面。
49 |
50 | 
51 |
52 | 那么对于这两者,我们应该使用哪个呢?
53 |
54 | 个人感觉应该优先使用 `#!/usr/bin/env python`,因为不是所有的机器的 python 解释器都是 `/usr/bin/python` 。
55 |
56 |
--------------------------------------------------------------------------------
/source/c01/c01_15.rst:
--------------------------------------------------------------------------------
1 | 1.15 /usr/bin/env python 有什么用?
2 | ===================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 我们经常会在别人的脚本或者项目的入口文件里看到第一行是下面这样
7 |
8 | .. code:: shell
9 |
10 | #!/usr/bin/python
11 |
12 | 或者这样
13 |
14 | .. code:: shell
15 |
16 | #!/usr/bin/env python
17 |
18 | 这两者有什么区别呢?
19 |
20 | 稍微接触过 linux 的人都知道 ``/usr/bin/python`` 就是我们执行 ``python``
21 | 进入console 模式里的 ``python``
22 |
23 | .. image:: http://image.iswbm.com/20200331184021.png
24 |
25 | 而当你在可执行文件头里使用 ``#!`` + ``/usr/bin/python``
26 | ,意思就是说你得用哪个软件 (python)来执行这个文件。
27 |
28 | 那么加和不加有什么区别呢?
29 |
30 | 不加的话,你每次执行这个脚本时,都得这样: ``python xx.py`` ,
31 |
32 | .. image:: http://image.iswbm.com/20200331185034.png
33 |
34 | 有没有一种方式?可以省去每次都加 ``python`` 呢?
35 |
36 | 当然有,你可以文件头里加上\ ``#!/usr/bin/python``
37 | ,那么当这个文件有可执行权限 时,只直接写这个脚本文件,就像下面这样。
38 |
39 | .. image:: http://image.iswbm.com/20200331184755.png
40 |
41 | 明白了这个后,再来看看 ``!/usr/bin/env python`` 这个 又是什么意思 ?
42 |
43 | 当我执行 ``env python`` 时,自动进入了 python console 的模式。
44 |
45 | .. image:: http://image.iswbm.com/20200331185741.png
46 |
47 | 这是为什么?和 直接执行 python 好像没什么区别呀
48 |
49 | 当你执行 ``env python`` 时,它其实会去 ``env | grep PATH`` 里(也就是
50 | /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin
51 | )这几个路径里去依次查找名为python的可执行文件。
52 |
53 | 找到一个就直接执行,上面我们的 python 路径是在 ``/usr/bin/python``
54 | 里,在 ``PATH`` 列表里倒数第二个目录下,所以当我在 ``/usr/local/sbin``
55 | 下创建一个名字也为 python 的可执行文件时,就会执行
56 | ``/usr/local/sbin/python`` 了。
57 |
58 | 具体演示过程,你可以看下面。
59 |
60 | .. image:: http://image.iswbm.com/20200331190224.png
61 |
62 | 那么对于这两者,我们应该使用哪个呢?
63 |
64 | 个人感觉应该优先使用 ``#!/usr/bin/env python``\ ,因为不是所有的机器的
65 | python 解释器都是 ``/usr/bin/python`` 。
66 |
--------------------------------------------------------------------------------
/source/c01/c01_16.md:
--------------------------------------------------------------------------------
1 | # 1.16 dict() 与 {} 生成空字典有什么区别?
2 | 
3 |
4 | 在初始化一个空字典时,有的人会写 dict(),而有的人会写成 {}
5 |
6 | 很多人会想当然的认为二者是等同的,但实际情况却不是这样的。
7 |
8 | 在运行效率上,{} 会比 dict() 快三倍左右。
9 |
10 | 使用 timeit 模块,可以轻松测出这个结果
11 |
12 | ```shell
13 | $ python -m timeit -n 1000000 -r 5 -v "dict()"
14 | raw times: 0.0996 0.0975 0.0969 0.0969 0.0994
15 | 1000000 loops, best of 5: 0.0969 usec per loop
16 | $
17 | $ python -m timeit -n 1000000 -r 5 -v "{}"
18 | raw times: 0.0305 0.0283 0.0272 0.03 0.0317
19 | 1000000 loops, best of 5: 0.0272 usec per loop
20 | ```
21 |
22 | 那为什么会这样呢?
23 |
24 | 探究这个过程,可以使用 dis 模块
25 |
26 | 当使用 {} 时
27 |
28 | ```shell
29 | $ cat demo.py
30 | {}
31 | $
32 | $ python -m dis demo.py
33 | 1 0 BUILD_MAP 0
34 | 2 POP_TOP
35 | 4 LOAD_CONST 0 (None)
36 | 6 RETURN_VALUE
37 | ```
38 |
39 | 当使用 dict() 时:
40 |
41 | ```shell
42 | $ cat demo.py
43 | dict()
44 | $
45 | $ python -m dis demo.py
46 | 1 0 LOAD_NAME 0 (dict)
47 | 2 CALL_FUNCTION 0
48 | 4 POP_TOP
49 | 6 LOAD_CONST 0 (None)
50 | 8 RETURN_VALUE
51 | ```
52 |
53 | 可以发现使用 dict(),会多了个调用函数的过程,而这个过程会有进出栈的操作,相对更加耗时。
54 |
55 |
--------------------------------------------------------------------------------
/source/c01/c01_16.rst:
--------------------------------------------------------------------------------
1 | 1.16 dict() 与 {} 生成空字典有什么区别?
2 | ========================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在初始化一个空字典时,有的人会写 dict(),而有的人会写成 {}
7 |
8 | 很多人会想当然的认为二者是等同的,但实际情况却不是这样的。
9 |
10 | 在运行效率上,{} 会比 dict() 快三倍左右。
11 |
12 | 使用 timeit 模块,可以轻松测出这个结果
13 |
14 | .. code:: shell
15 |
16 | $ python -m timeit -n 1000000 -r 5 -v "dict()"
17 | raw times: 0.0996 0.0975 0.0969 0.0969 0.0994
18 | 1000000 loops, best of 5: 0.0969 usec per loop
19 | $
20 | $ python -m timeit -n 1000000 -r 5 -v "{}"
21 | raw times: 0.0305 0.0283 0.0272 0.03 0.0317
22 | 1000000 loops, best of 5: 0.0272 usec per loop
23 |
24 | 那为什么会这样呢?
25 |
26 | 探究这个过程,可以使用 dis 模块
27 |
28 | 当使用 {} 时
29 |
30 | .. code:: shell
31 |
32 | $ cat demo.py
33 | {}
34 | $
35 | $ python -m dis demo.py
36 | 1 0 BUILD_MAP 0
37 | 2 POP_TOP
38 | 4 LOAD_CONST 0 (None)
39 | 6 RETURN_VALUE
40 |
41 | 当使用 dict() 时:
42 |
43 | .. code:: shell
44 |
45 | $ cat demo.py
46 | dict()
47 | $
48 | $ python -m dis demo.py
49 | 1 0 LOAD_NAME 0 (dict)
50 | 2 CALL_FUNCTION 0
51 | 4 POP_TOP
52 | 6 LOAD_CONST 0 (None)
53 | 8 RETURN_VALUE
54 |
55 | 可以发现使用
56 | dict(),会多了个调用函数的过程,而这个过程会有进出栈的操作,相对更加耗时。
57 |
--------------------------------------------------------------------------------
/source/c01/c01_17.md:
--------------------------------------------------------------------------------
1 | # 1.17 有趣但没啥用的 import 用法
2 | 
3 |
4 | import 是 Python 导包的方式。
5 |
6 | 你知道 Python 中内置了一些很有(wu)趣(liao)的包吗?
7 |
8 | **Hello World**
9 |
10 | ```
11 | >>> import __hello__
12 | Hello World!
13 | ```
14 |
15 | **Python之禅**
16 |
17 | ```
18 | >>> import this
19 |
20 | The Zen of Python, by Tim Peters
21 |
22 | Beautiful is better than ugly.
23 | Explicit is better than implicit.
24 | Simple is better than complex.
25 | Complex is better than complicated.
26 | Flat is better than nested.
27 | Sparse is better than dense.
28 | Readability counts.
29 | Special cases aren't special enough to break the rules.
30 | Although practicality beats purity.
31 | Errors should never pass silently.
32 | Unless explicitly silenced.
33 | In the face of ambiguity, refuse the temptation to guess.
34 | There should be one-- and preferably only one --obvious way to do it.
35 | Although that way may not be obvious at first unless you're Dutch.
36 | Now is better than never.
37 | Although never is often better than *right* now.
38 | If the implementation is hard to explain, it's a bad idea.
39 | If the implementation is easy to explain, it may be a good idea.
40 | Namespaces are one honking great idea -- let's do more of those!
41 | ```
42 |
43 | **反地心引力漫画**
44 |
45 | 在 cmd 窗口中导入`antigravity`
46 |
47 | ```
48 | >>> import antigravity
49 | ```
50 |
51 | 就会自动打开一个网页。
52 | 
53 |
54 |
55 |
--------------------------------------------------------------------------------
/source/c01/c01_17.rst:
--------------------------------------------------------------------------------
1 | 1.17 有趣但没啥用的 import 用法
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | import 是 Python 导包的方式。
7 |
8 | 你知道 Python 中内置了一些很有(wu)趣(liao)的包吗?
9 |
10 | **Hello World**
11 |
12 | ::
13 |
14 | >>> import __hello__
15 | Hello World!
16 |
17 | **Python之禅**
18 |
19 | ::
20 |
21 | >>> import this
22 |
23 | The Zen of Python, by Tim Peters
24 |
25 | Beautiful is better than ugly.
26 | Explicit is better than implicit.
27 | Simple is better than complex.
28 | Complex is better than complicated.
29 | Flat is better than nested.
30 | Sparse is better than dense.
31 | Readability counts.
32 | Special cases aren't special enough to break the rules.
33 | Although practicality beats purity.
34 | Errors should never pass silently.
35 | Unless explicitly silenced.
36 | In the face of ambiguity, refuse the temptation to guess.
37 | There should be one-- and preferably only one --obvious way to do it.
38 | Although that way may not be obvious at first unless you're Dutch.
39 | Now is better than never.
40 | Although never is often better than *right* now.
41 | If the implementation is hard to explain, it's a bad idea.
42 | If the implementation is easy to explain, it may be a good idea.
43 | Namespaces are one honking great idea -- let's do more of those!
44 |
45 | **反地心引力漫画**
46 |
47 | 在 cmd 窗口中导入\ ``antigravity``
48 |
49 | ::
50 |
51 | >>> import antigravity
52 |
53 | 就会自动打开一个网页。 |image1|
54 |
55 | .. |image1| image:: http://image.iswbm.com/20190511165735.png
56 |
--------------------------------------------------------------------------------
/source/c01/c01_18.md:
--------------------------------------------------------------------------------
1 | # 1.18 正负得负,负负得正
2 | 
3 |
4 | 从初中开始,我们就开始接触了`负数` ,并且都知道了`负负得正` 的思想。
5 |
6 | Python 作为一门高级语言,它的编写符合人类的思维逻辑,包括 `负负得正` 。
7 |
8 | ```python
9 | >>> 5-3
10 | 2
11 | >>> 5--3
12 | 8
13 | >>> 5+-3
14 | 2
15 | >>> 5++3
16 | 8
17 | >>> 5---3
18 | 2
19 | ```
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/source/c01/c01_18.rst:
--------------------------------------------------------------------------------
1 | 1.18 正负得负,负负得正
2 | =======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 从初中开始,我们就开始接触了\ ``负数`` ,并且都知道了\ ``负负得正``
7 | 的思想。
8 |
9 | Python 作为一门高级语言,它的编写符合人类的思维逻辑,包括 ``负负得正``
10 | 。
11 |
12 | .. code:: python
13 |
14 | >>> 5-3
15 | 2
16 | >>> 5--3
17 | 8
18 | >>> 5+-3
19 | 2
20 | >>> 5++3
21 | 8
22 | >>> 5---3
23 | 2
24 |
--------------------------------------------------------------------------------
/source/c01/c01_19.md:
--------------------------------------------------------------------------------
1 | # 1.19 return不一定都是函数的终点
2 | 
3 |
4 | 众所周知,try…finally… 的用法是:不管try里面是正常执行还是有报异常,最终都能保证finally能够执行。
5 |
6 | 同时我们又知道,一个函数里只要遇到 return 函数就会立马结束。
7 |
8 | 那问题就来了,以上这两种规则,如果同时存在,Python 解释器会如何选择?哪个优先级更高?
9 |
10 | 写个示例验证一下,就明白啦
11 |
12 | ```python
13 | >>> def func():
14 | ... try:
15 | ... return 'try'
16 | ... finally:
17 | ... return 'finally'
18 | ...
19 | >>> func()
20 | 'finally'
21 | ```
22 |
23 | 从输出中,我们可以发现:在try…finally…语句中,try中的 return 会被直接忽视(这里的 return 不是函数的终点),因为要保证 finally 能够执行。
24 |
25 | **如果 try 里的 return 真的是直接被忽视吗?**
26 |
27 | 我们都知道如果一个函数没有 return,会隐式的返回 None,假设 try 里的 return 真的是直接被忽视,那当finally 下没有显式的 return 的时候,是不是会返回None呢?
28 |
29 | 还是写个 示例来验证一下:
30 |
31 | ```python
32 | >>> def func():
33 | ... try:
34 | ... return 'try'
35 | ... finally:
36 | ... print('finally')
37 | ...
38 | >>>
39 | >>> func()
40 | finally
41 | 'try'
42 | >>>
43 | ```
44 |
45 | 从结果来看,当 finally 下没有 reutrn ,其实 try 里的 return 仍然还是有效的。
46 |
47 | 那结论就出来了,如果 finally 里有显式的 return,那么这个 return 会直接覆盖 try 里的 return,而如果 finally 里没有 显式的 return,那么 try 里的 return 仍然有效。
48 |
49 |
50 |
--------------------------------------------------------------------------------
/source/c01/c01_19.rst:
--------------------------------------------------------------------------------
1 | 1.19 return不一定都是函数的终点
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 众所周知,try…finally…
7 | 的用法是:不管try里面是正常执行还是有报异常,最终都能保证finally能够执行。
8 |
9 | 同时我们又知道,一个函数里只要遇到 return 函数就会立马结束。
10 |
11 | 那问题就来了,以上这两种规则,如果同时存在,Python
12 | 解释器会如何选择?哪个优先级更高?
13 |
14 | 写个示例验证一下,就明白啦
15 |
16 | .. code:: python
17 |
18 | >>> def func():
19 | ... try:
20 | ... return 'try'
21 | ... finally:
22 | ... return 'finally'
23 | ...
24 | >>> func()
25 | 'finally'
26 |
27 | 从输出中,我们可以发现:在try…finally…语句中,try中的 return
28 | 会被直接忽视(这里的 return 不是函数的终点),因为要保证 finally
29 | 能够执行。
30 |
31 | **如果 try 里的 return 真的是直接被忽视吗?**
32 |
33 | 我们都知道如果一个函数没有 return,会隐式的返回 None,假设 try 里的
34 | return 真的是直接被忽视,那当finally 下没有显式的 return
35 | 的时候,是不是会返回None呢?
36 |
37 | 还是写个 示例来验证一下:
38 |
39 | .. code:: python
40 |
41 | >>> def func():
42 | ... try:
43 | ... return 'try'
44 | ... finally:
45 | ... print('finally')
46 | ...
47 | >>>
48 | >>> func()
49 | finally
50 | 'try'
51 | >>>
52 |
53 | 从结果来看,当 finally 下没有 reutrn ,其实 try 里的 return
54 | 仍然还是有效的。
55 |
56 | 那结论就出来了,如果 finally 里有显式的 return,那么这个 return
57 | 会直接覆盖 try 里的 return,而如果 finally 里没有 显式的 return,那么
58 | try 里的 return 仍然有效。
59 |
--------------------------------------------------------------------------------
/source/c01/c01_20.md:
--------------------------------------------------------------------------------
1 | # 1.20 字符串里的缝隙是什么?
2 | 
3 |
4 | 在Python中求一个字符串里,某子字符(串)出现的次数。
5 |
6 | 大家都懂得使用 count() 函数,比如下面几个常规例子:
7 |
8 | ```python
9 | >>> "aabb".count("a")
10 | 2
11 | >>> "aabb".count("b")
12 | 2
13 | >>> "aabb".count("ab")
14 | 1
15 | ```
16 |
17 | 但是如果我想计算空字符串的个数呢?
18 |
19 | ```python
20 | >>> "aabb".count("")
21 | 5
22 | ```
23 |
24 | **奇怪了吧?**
25 |
26 | 不是应该返回 0 吗?怎么会返回 5?
27 |
28 | 实际上,在 Python 看来,两个字符之间都是一个空字符,通俗的说就是缝隙。
29 |
30 | 因此 对于 `aabb` 这个字符串在 Python 来看应该是这样的
31 |
32 | 
33 |
34 | 理解了这个“**缝隙**” 的概念后,以下这些就好理解了。
35 |
36 | ```python
37 | >>> (" " * 10).count("")
38 | 11
39 | >>>
40 | >>> "" in ""
41 | True
42 | >>>
43 | >>> "" in "M"
44 | True
45 | ```
46 |
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/source/c01/c01_20.rst:
--------------------------------------------------------------------------------
1 | 1.20 字符串里的缝隙是什么?
2 | ===========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在Python中求一个字符串里,某子字符(串)出现的次数。
7 |
8 | 大家都懂得使用 count() 函数,比如下面几个常规例子:
9 |
10 | .. code:: python
11 |
12 | >>> "aabb".count("a")
13 | 2
14 | >>> "aabb".count("b")
15 | 2
16 | >>> "aabb".count("ab")
17 | 1
18 |
19 | 但是如果我想计算空字符串的个数呢?
20 |
21 | .. code:: python
22 |
23 | >>> "aabb".count("")
24 | 5
25 |
26 | **奇怪了吧?**
27 |
28 | 不是应该返回 0 吗?怎么会返回 5?
29 |
30 | 实际上,在 Python 看来,两个字符之间都是一个空字符,通俗的说就是缝隙。
31 |
32 | 因此 对于 ``aabb`` 这个字符串在 Python 来看应该是这样的
33 |
34 | .. image:: http://image.iswbm.com/20200509172331.png
35 |
36 | 理解了这个“\ **缝隙**\ ” 的概念后,以下这些就好理解了。
37 |
38 | .. code:: python
39 |
40 | >>> (" " * 10).count("")
41 | 11
42 | >>>
43 | >>> "" in ""
44 | True
45 | >>>
46 | >>> "" in "M"
47 | True
48 |
--------------------------------------------------------------------------------
/source/c01/c01_21.md:
--------------------------------------------------------------------------------
1 | # 1.21 Python2下 也能使用 print(“”)
2 | 
3 |
4 | 可能会有不少人,觉得只有 Python 3 才可以使用 print(),而 Python 2 只能使用`print ""`。
5 |
6 | 但是其实并不是这样的。
7 |
8 | 在Python 2.6之前,只支持
9 |
10 | ```python
11 | print "hello"
12 | ```
13 |
14 | 在Python 2.6和2.7中,可以支持如下三种
15 |
16 | ```python
17 | print "hello"
18 | print("hello")
19 | print ("hello")
20 | ```
21 |
22 | 在Python3.x中,可以支持如下两种
23 |
24 | ```python
25 | print("hello")
26 | print ("hello")
27 | ```
28 |
29 | 虽然 在 Python 2.6+ 可以和 Python3.x+ 一样,像函数一样去调用 print ,但是这仅用于两个 python 版本之间的代码兼容,并不是说在 python2.6+下使用 print() 后,就成了函数。
30 |
31 |
32 |
--------------------------------------------------------------------------------
/source/c01/c01_21.rst:
--------------------------------------------------------------------------------
1 | 1.21 Python2下 也能使用 print(“”)
2 | =================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 可能会有不少人,觉得只有 Python 3 才可以使用 print(),而 Python 2
7 | 只能使用\ ``print ""``\ 。
8 |
9 | 但是其实并不是这样的。
10 |
11 | 在Python 2.6之前,只支持
12 |
13 | .. code:: python
14 |
15 | print "hello"
16 |
17 | 在Python 2.6和2.7中,可以支持如下三种
18 |
19 | .. code:: python
20 |
21 | print "hello"
22 | print("hello")
23 | print ("hello")
24 |
25 | 在Python3.x中,可以支持如下两种
26 |
27 | .. code:: python
28 |
29 | print("hello")
30 | print ("hello")
31 |
32 | 虽然 在 Python 2.6+ 可以和 Python3.x+ 一样,像函数一样去调用 print
33 | ,但是这仅用于两个 python 版本之间的代码兼容,并不是说在
34 | python2.6+下使用 print() 后,就成了函数。
35 |
--------------------------------------------------------------------------------
/source/c01/c01_22.md:
--------------------------------------------------------------------------------
1 | # 1.22 字母也玩起了障眼法
2 | 
3 |
4 | 以下我分别在 Python2.7 和 Python 3.7 的 console 模式下,运行了如下代码。
5 |
6 | **在Python 2.x 中**
7 |
8 | ```
9 | >>> valuе = 32
10 | File "", line 1
11 | valuе = 32
12 | ^
13 | SyntaxError: invalid syntax
14 | ```
15 |
16 | **在Python 3.x 中**
17 |
18 | ```
19 | >>> valuе = 32
20 | >>> value
21 | 11
22 | ```
23 |
24 | 什么?没有截图你不信?
25 |
26 | 
27 |
28 |
29 |
30 | 如果你在自己的电脑上尝试一下,结果可能是这样的
31 |
32 | 
33 |
34 |
35 |
36 | **怎么又好了呢?**
37 |
38 | 如果你想复现的话,请复制我这边给出的代码:`valuе = 32`
39 |
40 |
41 |
42 | **这是为什么呢?**
43 |
44 | 原因在于,我上面使用的 value 变量名里的 `е` 又不是我们熟悉的 `e`,它是 Cyrillic(西里尔)字母。
45 |
46 | ```
47 | >>> ord('е') # cyrillic 'e' (Ye)
48 | 1077
49 | >>> ord('e') # latin 'e', as used in English and typed using standard keyboard
50 | 101
51 | >>> 'е' == 'e'
52 | False
53 | ```
54 |
55 | 细思恐极,在这里可千万不要得罪同事们,万一离职的时候,对方把你项目里的 `e` 全局替换成 `e`,到时候你就哭去吧,肉眼根本看不出来嘛。
56 |
57 |
58 |
--------------------------------------------------------------------------------
/source/c01/c01_22.rst:
--------------------------------------------------------------------------------
1 | 1.22 字母也玩起了障眼法
2 | =======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 以下我分别在 Python2.7 和 Python 3.7 的 console 模式下,运行了如下代码。
7 |
8 | **在Python 2.x 中**
9 |
10 | ::
11 |
12 | >>> valuе = 32
13 | File "", line 1
14 | valuе = 32
15 | ^
16 | SyntaxError: invalid syntax
17 |
18 | **在Python 3.x 中**
19 |
20 | ::
21 |
22 | >>> valuе = 32
23 | >>> value
24 | 11
25 |
26 | 什么?没有截图你不信?
27 |
28 | .. image:: http://image.iswbm.com/20200509122954.png
29 |
30 | 如果你在自己的电脑上尝试一下,结果可能是这样的
31 |
32 | .. image:: http://image.iswbm.com/20200509123107.png
33 |
34 | **怎么又好了呢?**
35 |
36 | 如果你想复现的话,请复制我这边给出的代码:\ ``valuе = 32``
37 |
38 | **这是为什么呢?**
39 |
40 | 原因在于,我上面使用的 value 变量名里的 ``е`` 又不是我们熟悉的
41 | ``e``\ ,它是 Cyrillic(西里尔)字母。
42 |
43 | ::
44 |
45 | >>> ord('е') # cyrillic 'e' (Ye)
46 | 1077
47 | >>> ord('e') # latin 'e', as used in English and typed using standard keyboard
48 | 101
49 | >>> 'е' == 'e'
50 | False
51 |
52 | 细思恐极,在这里可千万不要得罪同事们,万一离职的时候,对方把你项目里的
53 | ``e`` 全局替换成 ``e``\ ,到时候你就哭去吧,肉眼根本看不出来嘛。
54 |
--------------------------------------------------------------------------------
/source/c01/c01_23.md:
--------------------------------------------------------------------------------
1 | # 1.23 数值与字符串的比较
2 | 
3 |
4 | 在 Python2 中,数字可以与字符串直接比较。结果是数值永远比字符串小。
5 |
6 | ```Python
7 | >>> 100000000 < ""
8 | True
9 | >>> 100000000 < "hello"
10 | True
11 | ```
12 |
13 | 但在 Python3 中,却不行。
14 |
15 | ```python
16 | >>> 100000000 < ""
17 | TypeError: '<' not supported between instances of 'int' and 'str'
18 | ```
19 |
20 |
21 |
22 |
--------------------------------------------------------------------------------
/source/c01/c01_23.rst:
--------------------------------------------------------------------------------
1 | 1.23 数值与字符串的比较
2 | =======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在 Python2 中,数字可以与字符串直接比较。结果是数值永远比字符串小。
7 |
8 | .. code:: python
9 |
10 | >>> 100000000 < ""
11 | True
12 | >>> 100000000 < "hello"
13 | True
14 |
15 | 但在 Python3 中,却不行。
16 |
17 | .. code:: python
18 |
19 | >>> 100000000 < ""
20 | TypeError: '<' not supported between instances of 'int' and 'str'
21 |
--------------------------------------------------------------------------------
/source/c01/c01_24.md:
--------------------------------------------------------------------------------
1 | # 1.24 时有时无的切片异常
2 |
3 | 
4 |
5 | 这是个简单例子,alist 只有5 个元素,当你取第 6 个元素时,会抛出索引异常。这与我们的认知一致。
6 |
7 | ```python
8 | >>> alist = [0, 1, 2, 3, 4]
9 | >>> alist[5]
10 | Traceback (most recent call last):
11 | File "", line 1, in
12 | IndexError: list index out of range
13 | ```
14 |
15 | 但是当你使用 alist[5:] 取一个区间时,即使 alist 并没有 第 6个元素,也不抛出异常,而是会返回一个新的列表。
16 |
17 | ```python
18 | >>> alist = [0, 1, 2, 3, 4]
19 | >>> alist[5:]
20 | []
21 | >>> alist[100:]
22 | []
23 | ```
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/source/c01/c01_24.rst:
--------------------------------------------------------------------------------
1 | 1.24 时有时无的切片异常
2 | =======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 这是个简单例子,alist 只有5 个元素,当你取第 6
7 | 个元素时,会抛出索引异常。这与我们的认知一致。
8 |
9 | .. code:: python
10 |
11 | >>> alist = [0, 1, 2, 3, 4]
12 | >>> alist[5]
13 | Traceback (most recent call last):
14 | File "", line 1, in
15 | IndexError: list index out of range
16 |
17 | 但是当你使用 alist[5:] 取一个区间时,即使 alist 并没有 第
18 | 6个元素,也不抛出异常,而是会返回一个新的列表。
19 |
20 | .. code:: python
21 |
22 | >>> alist = [0, 1, 2, 3, 4]
23 | >>> alist[5:]
24 | []
25 | >>> alist[100:]
26 | []
27 |
--------------------------------------------------------------------------------
/source/c01/c01_25.md:
--------------------------------------------------------------------------------
1 | # 1.25 迷一样的字符串
2 | 
3 |
4 | 示例一
5 |
6 | ```python
7 | # Python2.7
8 | >>> a = "Hello_Python"
9 | >>> id(a)
10 | 32045616
11 | >>> id("Hello" + "_" + "Python")
12 | 32045616
13 |
14 | # Python3.7
15 | >>> a = "Hello_Python"
16 | >>> id(a)
17 | 38764272
18 | >>> id("Hello" + "_" + "Python")
19 | 32045616
20 | ```
21 |
22 | 示例二
23 |
24 | ```python
25 | >>> a = "MING"
26 | >>> b = "MING"
27 | >>> a is b
28 | True
29 |
30 | # Python2.7
31 | >>> a, b = "MING!", "MING!"
32 | >>> a is b
33 | True
34 |
35 | # Python3.7
36 | >>> a, b = "MING!", "MING!"
37 | >>> a is b
38 | False
39 | ```
40 |
41 | 示例三
42 |
43 | ```python
44 | # Python2.7
45 | >>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'
46 | True
47 | >>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'
48 | False
49 |
50 | # Python3.7
51 | >>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'
52 | True
53 | >>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'
54 | True
55 | ```
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/source/c01/c01_25.rst:
--------------------------------------------------------------------------------
1 | 1.25 迷一样的字符串
2 | ===================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 示例一
7 |
8 | .. code:: python
9 |
10 | # Python2.7
11 | >>> a = "Hello_Python"
12 | >>> id(a)
13 | 32045616
14 | >>> id("Hello" + "_" + "Python")
15 | 32045616
16 |
17 | # Python3.7
18 | >>> a = "Hello_Python"
19 | >>> id(a)
20 | 38764272
21 | >>> id("Hello" + "_" + "Python")
22 | 32045616
23 |
24 | 示例二
25 |
26 | .. code:: python
27 |
28 | >>> a = "MING"
29 | >>> b = "MING"
30 | >>> a is b
31 | True
32 |
33 | # Python2.7
34 | >>> a, b = "MING!", "MING!"
35 | >>> a is b
36 | True
37 |
38 | # Python3.7
39 | >>> a, b = "MING!", "MING!"
40 | >>> a is b
41 | False
42 |
43 | 示例三
44 |
45 | .. code:: python
46 |
47 | # Python2.7
48 | >>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'
49 | True
50 | >>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'
51 | False
52 |
53 | # Python3.7
54 | >>> 'a' * 20 is 'aaaaaaaaaaaaaaaaaaaa'
55 | True
56 | >>> 'a' * 21 is 'aaaaaaaaaaaaaaaaaaaaa'
57 | True
58 |
--------------------------------------------------------------------------------
/source/c01/c01_26.md:
--------------------------------------------------------------------------------
1 | # 1.26 x 与 +x 等价吗?
2 | 
3 |
4 | 在大多数情况下,这个等式是成立的。
5 |
6 | ```python
7 | >>> n1 = 10086
8 | >>> n2 = +n1
9 | >>>
10 | >>> n1 == n2
11 | True
12 | ```
13 |
14 | 什么情况下,这个等式会不成立呢?
15 |
16 | 由于Counter的机制,`+` 用于两个 Counter 实例相加,而相加的结果如果元素的个数 `<=` 0,就会被丢弃。
17 |
18 | ```python
19 | >>> from collections import Counter
20 | >>> ct = Counter('abcdbcaa')
21 | >>> ct
22 | Counter({'a': 3, 'b': 2, 'c': 2, 'd': 1})
23 | >>> ct['c'] = 0
24 | >>> ct['d'] = -2
25 | >>>
26 | >>> ct
27 | Counter({'a': 3, 'b': 2, 'c': 0, 'd': -2})
28 | >>>
29 | >>> +ct
30 | Counter({'a': 3, 'b': 2})
31 | ```
32 |
33 |
34 |
35 |
36 |
--------------------------------------------------------------------------------
/source/c01/c01_26.rst:
--------------------------------------------------------------------------------
1 | 1.26 x 与 +x 等价吗?
2 | =====================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在大多数情况下,这个等式是成立的。
7 |
8 | .. code:: python
9 |
10 | >>> n1 = 10086
11 | >>> n2 = +n1
12 | >>>
13 | >>> n1 == n2
14 | True
15 |
16 | 什么情况下,这个等式会不成立呢?
17 |
18 | 由于Counter的机制,\ ``+`` 用于两个 Counter
19 | 实例相加,而相加的结果如果元素的个数 ``<=`` 0,就会被丢弃。
20 |
21 | .. code:: python
22 |
23 | >>> from collections import Counter
24 | >>> ct = Counter('abcdbcaa')
25 | >>> ct
26 | Counter({'a': 3, 'b': 2, 'c': 2, 'd': 1})
27 | >>> ct['c'] = 0
28 | >>> ct['d'] = -2
29 | >>>
30 | >>> ct
31 | Counter({'a': 3, 'b': 2, 'c': 0, 'd': -2})
32 | >>>
33 | >>> +ct
34 | Counter({'a': 3, 'b': 2})
35 |
--------------------------------------------------------------------------------
/source/c01/c01_27.md:
--------------------------------------------------------------------------------
1 | # 1.27 += 不等同于=+
2 | 
3 |
4 | 对列表 进行`+=` 操作相当于 extend,而使用 `=+` 操作是新增了一个列表。
5 |
6 | 因此会有如下两者的差异。
7 |
8 | ```python
9 | # =+
10 | >>> a = [1, 2, 3, 4]
11 | >>> b = a
12 | >>> a = a + [5, 6, 7, 8]
13 | >>> a
14 | [1, 2, 3, 4, 5, 6, 7, 8]
15 | >>> b
16 | [1, 2, 3, 4]
17 |
18 |
19 | # +=
20 | >>> a = [1, 2, 3, 4]
21 | >>> b = a
22 | >>> a += [5, 6, 7, 8]
23 | >>> a
24 | [1, 2, 3, 4, 5, 6, 7, 8]
25 | >>> b
26 | [1, 2, 3, 4, 5, 6, 7, 8]
27 | ```
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/source/c01/c01_27.rst:
--------------------------------------------------------------------------------
1 | 1.27 += 不等同于=+
2 | ==================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 对列表 进行\ ``+=`` 操作相当于 extend,而使用 ``=+``
7 | 操作是新增了一个列表。
8 |
9 | 因此会有如下两者的差异。
10 |
11 | .. code:: python
12 |
13 | # =+
14 | >>> a = [1, 2, 3, 4]
15 | >>> b = a
16 | >>> a = a + [5, 6, 7, 8]
17 | >>> a
18 | [1, 2, 3, 4, 5, 6, 7, 8]
19 | >>> b
20 | [1, 2, 3, 4]
21 |
22 |
23 | # +=
24 | >>> a = [1, 2, 3, 4]
25 | >>> b = a
26 | >>> a += [5, 6, 7, 8]
27 | >>> a
28 | [1, 2, 3, 4, 5, 6, 7, 8]
29 | >>> b
30 | [1, 2, 3, 4, 5, 6, 7, 8]
31 |
--------------------------------------------------------------------------------
/source/c01/c01_28.md:
--------------------------------------------------------------------------------
1 | # 1.28 循环中的局部变量泄露
2 | 
3 |
4 | 在Python 2中 x 的值在一个循环执行之后被改变了。
5 |
6 | ```python
7 | # Python2
8 | >>> x = 1
9 | >>> [x for x in range(5)]
10 | [0, 1, 2, 3, 4]
11 | >>> x
12 | 4
13 | ```
14 |
15 | 不过在Python3 中这个问题已经得到解决了。
16 |
17 | ```python
18 | # Python3
19 | >>> x = 1
20 | >>> [x for x in range(5)]
21 | [0, 1, 2, 3, 4]
22 | >>> x
23 | 1
24 | ```
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/source/c01/c01_28.rst:
--------------------------------------------------------------------------------
1 | 1.28 循环中的局部变量泄露
2 | =========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在Python 2中 x 的值在一个循环执行之后被改变了。
7 |
8 | .. code:: python
9 |
10 | # Python2
11 | >>> x = 1
12 | >>> [x for x in range(5)]
13 | [0, 1, 2, 3, 4]
14 | >>> x
15 | 4
16 |
17 | 不过在Python3 中这个问题已经得到解决了。
18 |
19 | .. code:: python
20 |
21 | # Python3
22 | >>> x = 1
23 | >>> [x for x in range(5)]
24 | [0, 1, 2, 3, 4]
25 | >>> x
26 | 1
27 |
--------------------------------------------------------------------------------
/source/c01/c01_29.md:
--------------------------------------------------------------------------------
1 | # 1.29 局部/全局变量傻傻分不清
2 | 
3 |
4 | 在开始讲之前,你可以试着运行一下下面这小段代码。
5 |
6 | ```python
7 | # demo.py
8 | a = 1
9 |
10 | def add():
11 | a += 1
12 |
13 | add()
14 | ```
15 |
16 | 看似没有毛病,但实则已经犯了一个很基础的问题,运行结果如下:
17 |
18 | ```python
19 | $ python demo.py
20 | Traceback (most recent call last):
21 | File "demo.py", line 6, in
22 | add()
23 | File "demo.py", line 4, in add
24 | a += 1
25 | UnboundLocalError: local variable 'a' referenced before assignment
26 | ```
27 |
28 | 回顾一下,什么是局部变量?在非全局下定义声明的变量都是局部变量。
29 |
30 | 当程序运行到 `a += 1` 时,Python 解释器就认为在函数内部要给 `a` 这个变量赋值,当然就把 `a` 当做局部变量了,但是做为局部变量的 a 还没有被还没被定义。
31 |
32 | 因此报错是正常的。
33 |
34 | 理解了上面的例子,给你留个思考题。为什么下面的代码不会报错呢?
35 |
36 | ```python
37 | $ cat demo.py
38 | a = 1
39 |
40 | def output():
41 | print(a)
42 |
43 | output()
44 |
45 | $ python demo.py
46 | 1
47 | ```
48 |
49 |
50 |
51 |
52 |
--------------------------------------------------------------------------------
/source/c01/c01_29.rst:
--------------------------------------------------------------------------------
1 | 1.29 局部/全局变量傻傻分不清
2 | ============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在开始讲之前,你可以试着运行一下下面这小段代码。
7 |
8 | .. code:: python
9 |
10 | # demo.py
11 | a = 1
12 |
13 | def add():
14 | a += 1
15 |
16 | add()
17 |
18 | 看似没有毛病,但实则已经犯了一个很基础的问题,运行结果如下:
19 |
20 | .. code:: python
21 |
22 | $ python demo.py
23 | Traceback (most recent call last):
24 | File "demo.py", line 6, in
25 | add()
26 | File "demo.py", line 4, in add
27 | a += 1
28 | UnboundLocalError: local variable 'a' referenced before assignment
29 |
30 | 回顾一下,什么是局部变量?在非全局下定义声明的变量都是局部变量。
31 |
32 | 当程序运行到 ``a += 1`` 时,Python 解释器就认为在函数内部要给 ``a``
33 | 这个变量赋值,当然就把 ``a`` 当做局部变量了,但是做为局部变量的 a
34 | 还没有被还没被定义。
35 |
36 | 因此报错是正常的。
37 |
38 | 理解了上面的例子,给你留个思考题。为什么下面的代码不会报错呢?
39 |
40 | .. code:: python
41 |
42 | $ cat demo.py
43 | a = 1
44 |
45 | def output():
46 | print(a)
47 |
48 | output()
49 |
50 | $ python demo.py
51 | 1
52 |
--------------------------------------------------------------------------------
/source/c01/c01_30.md:
--------------------------------------------------------------------------------
1 | # 1.30 break /continue 和 上下文管理器哪个优先级高?
2 | 
3 |
4 | 众所周知,在循环体中(无论是 for 还是 while),continue 会用来跳入下一个循环,而 break 则用来跳出某个循环体。
5 |
6 | 同时我们又知道:在上下文管理器中,被包裹的程序主体代码结束会运行上下文管理器中的一段代码(通常是资源的释放)。
7 |
8 | 但如果把上下文管理器放在一个循环体中,而在这个上下文管理器中执行了 break ,是否会直接跳出循环呢?
9 |
10 | 换句话说,上下文管理器与 break/continue 这两个规则哪一个优先级会更高一些?
11 |
12 | 这个问题其实不难,只要做一下试验都能轻易地得出答案,难就难在很多对这个答案都是半猜半疑,无法肯定地回答。
13 |
14 | 试验代码如下:
15 |
16 | ```python
17 | import time
18 | import contextlib
19 |
20 | @contextlib.contextmanager
21 | def runtime(value):
22 | time.sleep(1)
23 | print("start: a = " + str(value))
24 | yield
25 | print("end: a = " + str(value))
26 |
27 |
28 | a = 0
29 | while True:
30 | a+=1
31 | with runtime(a):
32 | if a % 2 == 0:
33 | break
34 | ```
35 |
36 | 从输出的结果来看,当 a = 2 时执行了 break ,此时的并不会直接跳出循环,依然要运行上下文管理器里清理释放资源的代码(示例中,我使用 print 来替代)。
37 |
38 | ```
39 | start: a = 1
40 | end: a = 1
41 | start: a = 2
42 | end: a = 2
43 | ```
44 |
45 |
46 |
47 | 另外还有几个与此类似的问题,我这里也直接给出答案,不再细说了
48 |
49 | 1. continue 与 break 一样,如果先遇到上下文管理器会先进行资源的释放
50 | 2. 上面只举例了 while 循环体,而 for 循环也是同样的。
51 |
52 |
53 |
--------------------------------------------------------------------------------
/source/c01/c01_30.rst:
--------------------------------------------------------------------------------
1 | 1.30 break /continue 和 上下文管理器哪个优先级高?
2 | ==================================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 众所周知,在循环体中(无论是 for 还是 while),continue
7 | 会用来跳入下一个循环,而 break 则用来跳出某个循环体。
8 |
9 | 同时我们又知道:在上下文管理器中,被包裹的程序主体代码结束会运行上下文管理器中的一段代码(通常是资源的释放)。
10 |
11 | 但如果把上下文管理器放在一个循环体中,而在这个上下文管理器中执行了 break
12 | ,是否会直接跳出循环呢?
13 |
14 | 换句话说,上下文管理器与 break/continue
15 | 这两个规则哪一个优先级会更高一些?
16 |
17 | 这个问题其实不难,只要做一下试验都能轻易地得出答案,难就难在很多对这个答案都是半猜半疑,无法肯定地回答。
18 |
19 | 试验代码如下:
20 |
21 | .. code:: python
22 |
23 | import time
24 | import contextlib
25 |
26 | @contextlib.contextmanager
27 | def runtime(value):
28 | time.sleep(1)
29 | print("start: a = " + str(value))
30 | yield
31 | print("end: a = " + str(value))
32 |
33 |
34 | a = 0
35 | while True:
36 | a+=1
37 | with runtime(a):
38 | if a % 2 == 0:
39 | break
40 |
41 | 从输出的结果来看,当 a = 2 时执行了 break
42 | ,此时的并不会直接跳出循环,依然要运行上下文管理器里清理释放资源的代码(示例中,我使用
43 | print 来替代)。
44 |
45 | ::
46 |
47 | start: a = 1
48 | end: a = 1
49 | start: a = 2
50 | end: a = 2
51 |
52 | 另外还有几个与此类似的问题,我这里也直接给出答案,不再细说了
53 |
54 | 1. continue 与 break 一样,如果先遇到上下文管理器会先进行资源的释放
55 | 2. 上面只举例了 while 循环体,而 for 循环也是同样的。
56 |
--------------------------------------------------------------------------------
/source/c01/c01_31.md:
--------------------------------------------------------------------------------
1 | # 1.31 如何像 awk一样分割字符串?
2 |
3 | 
4 |
5 | 若你使用过 Shell 中的 awk 工具,会发现用它来分割字符串是非常方便的。特别是多个连续空格会被当做一个处理。
6 |
7 | ```shell
8 | [root@localhost ~]# cat demo.txt
9 | hello world
10 | [root@localhost ~]#
11 | [root@localhost ~]# awk '{print$1,$2}' demo.txt
12 | hello world
13 | ```
14 |
15 | 可是转换到 Python 上面来呢?结果可能是这样的。
16 |
17 | ```python
18 | >>> msg='hello world'
19 | >>> msg.split(' ')
20 | ['hello', '', '', '', 'world']
21 | ```
22 |
23 | 与我预想的结果不符,多个空格会被分割多次。
24 |
25 | 那有什么办法可以达到 awk 一样的效果呢?
26 |
27 | 有两种方法。
28 |
29 | ## 第一种方法
30 |
31 | split函数不加参数,就能达到 awk 的效果
32 |
33 | ```python
34 | >>> msg='hello world'
35 | >>> msg.split()
36 | ['hello', 'world']
37 | ```
38 |
39 | 其实不仅是空格,严格来说,只要是空字符(比如制表符、换行符),就可以使用
40 |
41 | ```python
42 | >>> msg='hello \t \r\n world'
43 | >>> msg.split()
44 | ['hello', 'world']
45 | ```
46 |
47 | ## 第二种方法
48 |
49 | 使用 filter 来辅助,这种适用于所有的分隔符,下面以 `-` 为分隔符来举例。
50 |
51 | ```python
52 | >>> msg='hello----world'
53 | >>> msg.split('-')
54 | ['hello', '', '', '', 'world']
55 | >>>
56 | >>> filter(None, msg.split('-'))
57 | ['hello', 'world']
58 | ```
59 |
60 | 是不是很神奇,filter 印象中第一个参数接收的是 函数,这里直接传 None 居然有奇效。
61 |
62 | 查看了注释,原来是这个函数会适配 None 的情况,当第一个参数是None的时候,返回第二个参数(可迭代对象)中非空的值,非常方便。
63 |
64 | 
65 |
66 | 换用函数的写法,可以这样
67 |
68 | ```python
69 | >>> msg='hello----world'
70 | >>> msg.split('-')
71 | ['hello', '', '', '', 'world']
72 | >>>
73 | >>> filter(lambda item: True if item else False, msg.split('-'))
74 | ['hello', 'world']
75 | ```
76 |
77 |
78 |
79 |
80 |
81 |
--------------------------------------------------------------------------------
/source/c01/c01_31.rst:
--------------------------------------------------------------------------------
1 | 1.31 如何像 awk一样分割字符串?
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 若你使用过 Shell 中的 awk
7 | 工具,会发现用它来分割字符串是非常方便的。特别是多个连续空格会被当做一个处理。
8 |
9 | .. code:: shell
10 |
11 | [root@localhost ~]# cat demo.txt
12 | hello world
13 | [root@localhost ~]#
14 | [root@localhost ~]# awk '{print$1,$2}' demo.txt
15 | hello world
16 |
17 | 可是转换到 Python 上面来呢?结果可能是这样的。
18 |
19 | .. code:: python
20 |
21 | >>> msg='hello world'
22 | >>> msg.split(' ')
23 | ['hello', '', '', '', 'world']
24 |
25 | 与我预想的结果不符,多个空格会被分割多次。
26 |
27 | 那有什么办法可以达到 awk 一样的效果呢?
28 |
29 | 有两种方法。
30 |
31 | 第一种方法
32 | ----------
33 |
34 | split函数不加参数,就能达到 awk 的效果
35 |
36 | .. code:: python
37 |
38 | >>> msg='hello world'
39 | >>> msg.split()
40 | ['hello', 'world']
41 |
42 | 其实不仅是空格,严格来说,只要是空字符(比如制表符、换行符),就可以使用
43 |
44 | .. code:: python
45 |
46 | >>> msg='hello \t \r\n world'
47 | >>> msg.split()
48 | ['hello', 'world']
49 |
50 | 第二种方法
51 | ----------
52 |
53 | 使用 filter 来辅助,这种适用于所有的分隔符,下面以 ``-``
54 | 为分隔符来举例。
55 |
56 | .. code:: python
57 |
58 | >>> msg='hello----world'
59 | >>> msg.split('-')
60 | ['hello', '', '', '', 'world']
61 | >>>
62 | >>> filter(None, msg.split('-'))
63 | ['hello', 'world']
64 |
65 | 是不是很神奇,filter 印象中第一个参数接收的是 函数,这里直接传 None
66 | 居然有奇效。
67 |
68 | 查看了注释,原来是这个函数会适配 None
69 | 的情况,当第一个参数是None的时候,返回第二个参数(可迭代对象)中非空的值,非常方便。
70 |
71 | .. image:: http://image.iswbm.com/20200821173708.png
72 |
73 | 换用函数的写法,可以这样
74 |
75 | .. code:: python
76 |
77 | >>> msg='hello----world'
78 | >>> msg.split('-')
79 | ['hello', '', '', '', 'world']
80 | >>>
81 | >>> filter(lambda item: True if item else False, msg.split('-'))
82 | ['hello', 'world']
83 |
--------------------------------------------------------------------------------
/source/c01/c01_32.md:
--------------------------------------------------------------------------------
1 | # 1.32 如何让大数变得更易于阅读?
2 |
3 | 
4 |
5 | 当一个数非常大时,可能过百万,也可能上亿,太多位的数字 ,会给我们阅读带来很大的障碍。
6 |
7 | 比如下面这个数,你能一下子说出它是多少万呢,还是多少亿呢?
8 |
9 | ```
10 | 281028344
11 | ```
12 |
13 | 是不是没法很快的辩识出来?
14 |
15 | 这时候,你可以使用 `_` 来辅助标识,写成这样子就清晰多了
16 |
17 | ```
18 | 281_028_344
19 | ```
20 |
21 | 关键这种写法,在代码中并不会报错噢(Python2 不支持)
22 |
23 | ```python
24 | >>> number=281_028_344
25 | >>> number
26 | 281028344
27 | ```
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/source/c01/c01_32.rst:
--------------------------------------------------------------------------------
1 | 1.32 如何让大数变得更易于阅读?
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当一个数非常大时,可能过百万,也可能上亿,太多位的数字
7 | ,会给我们阅读带来很大的障碍。
8 |
9 | 比如下面这个数,你能一下子说出它是多少万呢,还是多少亿呢?
10 |
11 | ::
12 |
13 | 281028344
14 |
15 | 是不是没法很快的辩识出来?
16 |
17 | 这时候,你可以使用 ``_`` 来辅助标识,写成这样子就清晰多了
18 |
19 | ::
20 |
21 | 281_028_344
22 |
23 | 关键这种写法,在代码中并不会报错噢(Python2 不支持)
24 |
25 | .. code:: python
26 |
27 | >>> number=281_028_344
28 | >>> number
29 | 281028344
30 |
--------------------------------------------------------------------------------
/source/c02/c02_01.md:
--------------------------------------------------------------------------------
1 | # 2.1 懒人必备技能:使用 “_”
2 | 
3 |
4 | 对于 `_` ,大家对于他的印象都是用于 **占位符**,省得为一个不需要用到的变量,绞尽脑汁的想变量名。
5 |
6 | 今天要介绍的是他的第二种用法,就是在交互式模式下的应用。
7 |
8 | 示例如下:
9 |
10 | ```python
11 | >>> 3 + 4
12 | 7
13 | >>> _
14 | 7
15 | >>> name='iswbm'
16 | >>> name
17 | 'iswbm'
18 | >>> _
19 | 'iswbm'
20 | ```
21 |
22 | 它可以返回上一次的运行结果。
23 |
24 | 但是,如果是print函数打印出来的就不行了。
25 |
26 | ```python
27 | >>> 3 + 4
28 | 7
29 | >>> _
30 | 7
31 | >>> print("iswbm")
32 | iswbm
33 | >>> _
34 | 7
35 | ```
36 |
37 | 我自己写了个例子,验证了下,用`__repr__`输出的内容可以被获取到的。
38 | 首先,在我们的目录下,写一个文件 demo.py。内容如下
39 |
40 | ```python
41 | # demo.py
42 | class mytest():
43 | def __str__(self):
44 | return "hello"
45 |
46 | def __repr__(self):
47 | return "world"
48 | ```
49 |
50 | 然后在这个目录下进入交互式环境。
51 |
52 | ```python
53 | >>> import demo
54 | >>> mt=demo.mytest()
55 | >>> mt
56 | world
57 | >>> print(mt)
58 | hello
59 | >>> _
60 | world
61 | ```
62 |
63 | 知道这两个魔法方法的人,一看就明白了,这里不再解释啦。
64 |
65 |
66 |
--------------------------------------------------------------------------------
/source/c02/c02_01.rst:
--------------------------------------------------------------------------------
1 | 2.1 懒人必备技能:使用 “_”
2 | ==========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 对于 ``_`` ,大家对于他的印象都是用于
7 | **占位符**\ ,省得为一个不需要用到的变量,绞尽脑汁的想变量名。
8 |
9 | 今天要介绍的是他的第二种用法,就是在交互式模式下的应用。
10 |
11 | 示例如下:
12 |
13 | .. code:: python
14 |
15 | >>> 3 + 4
16 | 7
17 | >>> _
18 | 7
19 | >>> name='iswbm'
20 | >>> name
21 | 'iswbm'
22 | >>> _
23 | 'iswbm'
24 |
25 | 它可以返回上一次的运行结果。
26 |
27 | 但是,如果是print函数打印出来的就不行了。
28 |
29 | .. code:: python
30 |
31 | >>> 3 + 4
32 | 7
33 | >>> _
34 | 7
35 | >>> print("iswbm")
36 | iswbm
37 | >>> _
38 | 7
39 |
40 | 我自己写了个例子,验证了下,用\ ``__repr__``\ 输出的内容可以被获取到的。
41 | 首先,在我们的目录下,写一个文件 demo.py。内容如下
42 |
43 | .. code:: python
44 |
45 | # demo.py
46 | class mytest():
47 | def __str__(self):
48 | return "hello"
49 |
50 | def __repr__(self):
51 | return "world"
52 |
53 | 然后在这个目录下进入交互式环境。
54 |
55 | .. code:: python
56 |
57 | >>> import demo
58 | >>> mt=demo.mytest()
59 | >>> mt
60 | world
61 | >>> print(mt)
62 | hello
63 | >>> _
64 | world
65 |
66 | 知道这两个魔法方法的人,一看就明白了,这里不再解释啦。
67 |
--------------------------------------------------------------------------------
/source/c02/c02_02.md:
--------------------------------------------------------------------------------
1 | # 2.2 最快查看包搜索路径的方式
2 | 
3 |
4 | 当你使用 import 导入一个包或模块时,Python 会去一些目录下查找,而这些目录是有优先级顺序的,正常人会使用 sys.path 查看。
5 |
6 | ```python
7 | >>> import sys
8 | >>> from pprint import pprint
9 | >>> pprint(sys.path)
10 | ['',
11 | '/usr/local/Python3.7/lib/python37.zip',
12 | '/usr/local/Python3.7/lib/python3.7',
13 | '/usr/local/Python3.7/lib/python3.7/lib-dynload',
14 | '/home/wangbm/.local/lib/python3.7/site-packages',
15 | '/usr/local/Python3.7/lib/python3.7/site-packages']
16 | >>>
17 | ```
18 |
19 | 那有没有更快的方式呢?
20 |
21 | 我这有一种连 console 模式都不用进入的方法呢?
22 |
23 | 你可能会想到这种,但这本质上与上面并无区别
24 |
25 | ```python
26 | [wangbm@localhost ~]$ python -c "print('\n'.join(__import__('sys').path))"
27 |
28 | /usr/lib/python2.7/site-packages/pip-18.1-py2.7.egg
29 | /usr/lib/python2.7/site-packages/redis-3.0.1-py2.7.egg
30 | /usr/lib64/python27.zip
31 | /usr/lib64/python2.7
32 | /usr/lib64/python2.7/plat-linux2
33 | /usr/lib64/python2.7/lib-tk
34 | /usr/lib64/python2.7/lib-old
35 | /usr/lib64/python2.7/lib-dynload
36 | /home/wangbm/.local/lib/python2.7/site-packages
37 | /usr/lib64/python2.7/site-packages
38 | /usr/lib64/python2.7/site-packages/gtk-2.0
39 | /usr/lib/python2.7/site-packages
40 | ```
41 |
42 | 这里我要介绍的是比上面两种都方便得多的方法,一行命令即可解决
43 |
44 | ```shell
45 | [wangbm@localhost ~]$ python3 -m site
46 | sys.path = [
47 | '/home/wangbm',
48 | '/usr/local/Python3.7/lib/python37.zip',
49 | '/usr/local/Python3.7/lib/python3.7',
50 | '/usr/local/Python3.7/lib/python3.7/lib-dynload',
51 | '/home/wangbm/.local/lib/python3.7/site-packages',
52 | '/usr/local/Python3.7/lib/python3.7/site-packages',
53 | ]
54 | USER_BASE: '/home/wangbm/.local' (exists)
55 | USER_SITE: '/home/wangbm/.local/lib/python3.7/site-packages' (exists)
56 | ENABLE_USER_SITE: True
57 | ```
58 |
59 | 从输出你可以发现,这个列的路径会比 sys.path 更全,它包含了用户环境的目录。
60 |
61 |
62 |
--------------------------------------------------------------------------------
/source/c02/c02_02.rst:
--------------------------------------------------------------------------------
1 | 2.2 最快查看包搜索路径的方式
2 | ============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当你使用 import 导入一个包或模块时,Python
7 | 会去一些目录下查找,而这些目录是有优先级顺序的,正常人会使用 sys.path
8 | 查看。
9 |
10 | .. code:: python
11 |
12 | >>> import sys
13 | >>> from pprint import pprint
14 | >>> pprint(sys.path)
15 | ['',
16 | '/usr/local/Python3.7/lib/python37.zip',
17 | '/usr/local/Python3.7/lib/python3.7',
18 | '/usr/local/Python3.7/lib/python3.7/lib-dynload',
19 | '/home/wangbm/.local/lib/python3.7/site-packages',
20 | '/usr/local/Python3.7/lib/python3.7/site-packages']
21 | >>>
22 |
23 | 那有没有更快的方式呢?
24 |
25 | 我这有一种连 console 模式都不用进入的方法呢?
26 |
27 | 你可能会想到这种,但这本质上与上面并无区别
28 |
29 | .. code:: python
30 |
31 | [wangbm@localhost ~]$ python -c "print('\n'.join(__import__('sys').path))"
32 |
33 | /usr/lib/python2.7/site-packages/pip-18.1-py2.7.egg
34 | /usr/lib/python2.7/site-packages/redis-3.0.1-py2.7.egg
35 | /usr/lib64/python27.zip
36 | /usr/lib64/python2.7
37 | /usr/lib64/python2.7/plat-linux2
38 | /usr/lib64/python2.7/lib-tk
39 | /usr/lib64/python2.7/lib-old
40 | /usr/lib64/python2.7/lib-dynload
41 | /home/wangbm/.local/lib/python2.7/site-packages
42 | /usr/lib64/python2.7/site-packages
43 | /usr/lib64/python2.7/site-packages/gtk-2.0
44 | /usr/lib/python2.7/site-packages
45 |
46 | 这里我要介绍的是比上面两种都方便得多的方法,一行命令即可解决
47 |
48 | .. code:: shell
49 |
50 | [wangbm@localhost ~]$ python3 -m site
51 | sys.path = [
52 | '/home/wangbm',
53 | '/usr/local/Python3.7/lib/python37.zip',
54 | '/usr/local/Python3.7/lib/python3.7',
55 | '/usr/local/Python3.7/lib/python3.7/lib-dynload',
56 | '/home/wangbm/.local/lib/python3.7/site-packages',
57 | '/usr/local/Python3.7/lib/python3.7/site-packages',
58 | ]
59 | USER_BASE: '/home/wangbm/.local' (exists)
60 | USER_SITE: '/home/wangbm/.local/lib/python3.7/site-packages' (exists)
61 | ENABLE_USER_SITE: True
62 |
63 | 从输出你可以发现,这个列的路径会比 sys.path
64 | 更全,它包含了用户环境的目录。
65 |
--------------------------------------------------------------------------------
/source/c02/c02_04.md:
--------------------------------------------------------------------------------
1 | # 2.4 命令行式执行 Python 代码
2 | 
3 |
4 | 有时候你只是想验证一小段 Python 代码是否可用时,通常有两种方法
5 |
6 | 1. 输入 python 回车,进入 console 模式,然后敲入代码进行验证
7 | 2. 将你的代码写入 demo.py 脚本中,然后使用 python demo.py 验证
8 |
9 | 其实还有一种更简单的方法,比如我要计算一个字符串的md5
10 |
11 | ```shell
12 | $ python -c "import hashlib;print(hashlib.md5('hello').hexdigest())"
13 | 5d41402abc4b2a76b9719d911017c592
14 | ```
15 |
16 | 只要加 -c 参数,就可以输入你的 Python 代码了。
17 |
18 |
19 |
--------------------------------------------------------------------------------
/source/c02/c02_04.rst:
--------------------------------------------------------------------------------
1 | 2.4 命令行式执行 Python 代码
2 | ============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 有时候你只是想验证一小段 Python 代码是否可用时,通常有两种方法
7 |
8 | 1. 输入 python 回车,进入 console 模式,然后敲入代码进行验证
9 | 2. 将你的代码写入 demo.py 脚本中,然后使用 python demo.py 验证
10 |
11 | 其实还有一种更简单的方法,比如我要计算一个字符串的md5
12 |
13 | .. code:: shell
14 |
15 | $ python -c "import hashlib;print(hashlib.md5('hello').hexdigest())"
16 | 5d41402abc4b2a76b9719d911017c592
17 |
18 | 只要加 -c 参数,就可以输入你的 Python 代码了。
19 |
--------------------------------------------------------------------------------
/source/c02/c02_05.md:
--------------------------------------------------------------------------------
1 | # 2.5 用调试模式执行脚本
2 | 
3 |
4 | 当你使用 pdb 进行脚本的调试时,你可能会先在目标代码处输入 `import pdb;pdb.set_trace()` 来设置断点。
5 |
6 | 除此之外,还有一种方法,就是使用 `-m pdb`
7 |
8 | ```shell
9 | $ python -m pdb demo.py
10 | > /Users/MING/demo.py(1)()
11 | -> import sys
12 | (Pdb)
13 | ```
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/source/c02/c02_05.rst:
--------------------------------------------------------------------------------
1 | 2.5 用调试模式执行脚本
2 | ======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当你使用 pdb 进行脚本的调试时,你可能会先在目标代码处输入
7 | ``import pdb;pdb.set_trace()`` 来设置断点。
8 |
9 | 除此之外,还有一种方法,就是使用 ``-m pdb``
10 |
11 | .. code:: shell
12 |
13 | $ python -m pdb demo.py
14 | > /Users/MING/demo.py(1)()
15 | -> import sys
16 | (Pdb)
17 |
--------------------------------------------------------------------------------
/source/c02/c02_06.md:
--------------------------------------------------------------------------------
1 | # 2.6 如何快速搭建 HTTP 服务器
2 | 
3 |
4 | 搭建FTP,或者是搭建网络文件系统,这些方法都能够实现Linux的目录共享。但是FTP和网络文件系统的功能都过于强大,因此它们都有一些不够方便的地方。比如你想快速共享Linux系统的某个目录给整个项目团队,还想在一分钟内做到,怎么办?很简单,使用Python中的SimpleHTTPServer。
5 |
6 | SimpleHTTPServer是Python 2自带的一个模块,是Python的Web服务器。它在Python 3已经合并到http.server模块中。具体例子如下,如不指定端口,则默认是8000端口。
7 |
8 | ```python
9 | # python2
10 | python -m SimpleHTTPServer 8888
11 |
12 | # python3
13 | python3 -m http.server 8888
14 | ```
15 |
16 | 
17 |
18 | SimpleHTTPServer有一个特性,如果待共享的目录下有index.html,那么index.html文件会被视为默认主页;如果不存在index.html文件,那么就会显示整个目录列表。
19 |
20 |
21 |
--------------------------------------------------------------------------------
/source/c02/c02_06.rst:
--------------------------------------------------------------------------------
1 | 2.6 如何快速搭建 HTTP 服务器
2 | ============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 搭建FTP,或者是搭建网络文件系统,这些方法都能够实现Linux的目录共享。但是FTP和网络文件系统的功能都过于强大,因此它们都有一些不够方便的地方。比如你想快速共享Linux系统的某个目录给整个项目团队,还想在一分钟内做到,怎么办?很简单,使用Python中的SimpleHTTPServer。
7 |
8 | SimpleHTTPServer是Python
9 | 2自带的一个模块,是Python的Web服务器。它在Python
10 | 3已经合并到http.server模块中。具体例子如下,如不指定端口,则默认是8000端口。
11 |
12 | .. code:: python
13 |
14 | # python2
15 | python -m SimpleHTTPServer 8888
16 |
17 | # python3
18 | python3 -m http.server 8888
19 |
20 | .. image:: http://image.iswbm.com/20190511165716.png
21 |
22 | SimpleHTTPServer有一个特性,如果待共享的目录下有index.html,那么index.html文件会被视为默认主页;如果不存在index.html文件,那么就会显示整个目录列表。
23 |
--------------------------------------------------------------------------------
/source/c02/c02_07.md:
--------------------------------------------------------------------------------
1 | # 2.7 快速构建 HTML 帮助文档
2 | 
3 |
4 | 当你不知道一个内置模块如何使用时,会怎么做呢?
5 |
6 | 百度?Google?
7 |
8 | 其实完全没必要,这里教你一个离线学习 Python 模块的方法。
9 |
10 | 是的,你没有听错。
11 |
12 | 就算没有外网网络也能学习 Python 模块.
13 |
14 | 你只要在命令行下输入 `python -m pydoc -p xxx` 命令即可开启一个 HTTP 服务,xxx 为端口,你可以自己指定。
15 |
16 | ```shell
17 | $ python -m pydoc -p 5200
18 | pydoc server ready at http://localhost:5200/
19 | ```
20 |
21 | 帮助文档的效果如下
22 |
23 | 
24 |
25 | ##
26 |
27 |
28 |
--------------------------------------------------------------------------------
/source/c02/c02_07.rst:
--------------------------------------------------------------------------------
1 | 2.7 快速构建 HTML 帮助文档
2 | ==========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当你不知道一个内置模块如何使用时,会怎么做呢?
7 |
8 | 百度?Google?
9 |
10 | 其实完全没必要,这里教你一个离线学习 Python 模块的方法。
11 |
12 | 是的,你没有听错。
13 |
14 | 就算没有外网网络也能学习 Python 模块.
15 |
16 | 你只要在命令行下输入 ``python -m pydoc -p xxx`` 命令即可开启一个 HTTP
17 | 服务,xxx 为端口,你可以自己指定。
18 |
19 | .. code:: shell
20 |
21 | $ python -m pydoc -p 5200
22 | pydoc server ready at http://localhost:5200/
23 |
24 | 帮助文档的效果如下
25 |
26 | .. image:: http://image.iswbm.com/20200718191249.png
27 |
--------------------------------------------------------------------------------
/source/c02/c02_08.md:
--------------------------------------------------------------------------------
1 | # 2.8 最正确且优雅的装包方法
2 | 
3 |
4 | 当你使用 pip 来安装第三方的模块时,通常会使用这样的命令
5 |
6 | ```shell
7 | $ pip install requests
8 | ```
9 |
10 | 此时如果你的环境中有 Python2 也有 Python 3,那你使用这条命令安装的包是安装 Python2 呢?还是安装到 Python 3 呢?
11 |
12 | 就算你的环境上没有安装 Python2,那也有可能存在着多个版本的 Python 吧?比如安装了 Python3.8,也安装了 Python3.9,那你安装包时就会很困惑,我到底把包安装在了哪里?
13 |
14 | 但若你使用这样的命令去安装,就没有了这样的烦恼了
15 |
16 | ```shell
17 | # 在 python2 中安装
18 | $ python -m pip install requests
19 |
20 | # 在 python3 中安装
21 | $ python3 -m pip install requests
22 |
23 | # 在 python3.8 中安装
24 | $ python3.8 -m pip install requests
25 |
26 | # 在 python3.9 中安装
27 | $ python3.9 -m pip install requests
28 | ```
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/source/c02/c02_08.rst:
--------------------------------------------------------------------------------
1 | 2.8 最正确且优雅的装包方法
2 | ==========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当你使用 pip 来安装第三方的模块时,通常会使用这样的命令
7 |
8 | .. code:: shell
9 |
10 | $ pip install requests
11 |
12 | 此时如果你的环境中有 Python2 也有 Python
13 | 3,那你使用这条命令安装的包是安装 Python2 呢?还是安装到 Python 3 呢?
14 |
15 | 就算你的环境上没有安装 Python2,那也有可能存在着多个版本的 Python
16 | 吧?比如安装了 Python3.8,也安装了
17 | Python3.9,那你安装包时就会很困惑,我到底把包安装在了哪里?
18 |
19 | 但若你使用这样的命令去安装,就没有了这样的烦恼了
20 |
21 | .. code:: shell
22 |
23 | # 在 python2 中安装
24 | $ python -m pip install requests
25 |
26 | # 在 python3 中安装
27 | $ python3 -m pip install requests
28 |
29 | # 在 python3.8 中安装
30 | $ python3.8 -m pip install requests
31 |
32 | # 在 python3.9 中安装
33 | $ python3.9 -m pip install requests
34 |
--------------------------------------------------------------------------------
/source/c02/c02_09.md:
--------------------------------------------------------------------------------
1 | # 2.9 往 Python Shell 中传入参数
2 | 
3 |
4 | 往一个 Python 脚本传入参数,是一件非常简单的事情。
5 |
6 | 比如这样:
7 |
8 | ```shell
9 | $ python demo.py arg1 arg2
10 | ```
11 |
12 | 我在验证一些简单的 Python 代码时,喜欢使用 Python Shell 。
13 |
14 | 那有没有办法在使用 Python Shell 时,向上面传递参数一样,传入参数呢?
15 |
16 | 经过我的摸索,终于找到了方法,具体方法如下:
17 |
18 | 
19 |
20 | ##
21 |
22 |
23 |
--------------------------------------------------------------------------------
/source/c02/c02_09.rst:
--------------------------------------------------------------------------------
1 | 2.9 往 Python Shell 中传入参数
2 | ==============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 往一个 Python 脚本传入参数,是一件非常简单的事情。
7 |
8 | 比如这样:
9 |
10 | .. code:: shell
11 |
12 | $ python demo.py arg1 arg2
13 |
14 | 我在验证一些简单的 Python 代码时,喜欢使用 Python Shell 。
15 |
16 | 那有没有办法在使用 Python Shell 时,向上面传递参数一样,传入参数呢?
17 |
18 | 经过我的摸索,终于找到了方法,具体方法如下:
19 |
20 | .. image:: http://image.iswbm.com/20200801195158.png
21 |
--------------------------------------------------------------------------------
/source/c02/c02_10.md:
--------------------------------------------------------------------------------
1 | # 2.10 让脚本报错后立即进入调试模式
2 | 
3 |
4 | 当你在使用 `python xxx.py` 这样的方法,执行 Python 脚本时,若因为代码 bug 导致异常未捕获,那整个程序便会终止退出。
5 |
6 | 这个时候,我们通常会去排查是什么原因导致的程序崩溃。
7 |
8 | 大家都知道,排查问题的思路,第一步肯定是去查看日志,若这个 bug 隐藏得比较深,只有在特定场景下才会现身,那么还需要开发者,复现这个 bug,方能优化代码。
9 |
10 | 复现有时候很难,有时候虽然简单,但是要伪造各种数据,相当麻烦。
11 |
12 | **如果有一种方法能在程序崩溃后,立马进入调试模式该有多好啊?**
13 |
14 | 明哥都这么问了,那肯定是带着解决方案来的。
15 |
16 | 只要你在执行脚本行,加上 `-i` 参数,即可在脚本执行完毕后进入 Python Shell 模式,方便你进行调试。
17 |
18 | 具体演示如下:
19 |
20 | 
21 |
22 | 需要注意的是:脚本执行完毕,有两种情况:
23 |
24 | 1. 正常退出
25 | 2. 异常退出
26 |
27 | 这两种都会进入 Python Shell,如果脚本并无异常,最终也会进入 Python Shell 模式,需要你手动退出
28 |
29 | 
30 |
31 | 如果希望脚本正确完成时自动退出,可以在脚本最后加上一行`__import__("os")._exit(0)`
32 |
33 |
34 |
--------------------------------------------------------------------------------
/source/c02/c02_10.rst:
--------------------------------------------------------------------------------
1 | 2.10 让脚本报错后立即进入调试模式
2 | =================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当你在使用 ``python xxx.py`` 这样的方法,执行 Python 脚本时,若因为代码
7 | bug 导致异常未捕获,那整个程序便会终止退出。
8 |
9 | 这个时候,我们通常会去排查是什么原因导致的程序崩溃。
10 |
11 | 大家都知道,排查问题的思路,第一步肯定是去查看日志,若这个 bug
12 | 隐藏得比较深,只有在特定场景下才会现身,那么还需要开发者,复现这个
13 | bug,方能优化代码。
14 |
15 | 复现有时候很难,有时候虽然简单,但是要伪造各种数据,相当麻烦。
16 |
17 | **如果有一种方法能在程序崩溃后,立马进入调试模式该有多好啊?**
18 |
19 | 明哥都这么问了,那肯定是带着解决方案来的。
20 |
21 | 只要你在执行脚本行,加上 ``-i`` 参数,即可在脚本执行完毕后进入 Python
22 | Shell 模式,方便你进行调试。
23 |
24 | 具体演示如下:
25 |
26 | .. image:: http://image.iswbm.com/20200801195950.png
27 |
28 | 需要注意的是:脚本执行完毕,有两种情况:
29 |
30 | 1. 正常退出
31 | 2. 异常退出
32 |
33 | 这两种都会进入 Python Shell,如果脚本并无异常,最终也会进入 Python Shell
34 | 模式,需要你手动退出
35 |
36 | .. image:: http://image.iswbm.com/20200801201110.png
37 |
38 | 如果希望脚本正确完成时自动退出,可以在脚本最后加上一行\ ``__import__("os")._exit(0)``
39 |
--------------------------------------------------------------------------------
/source/c02/c02_11.md:
--------------------------------------------------------------------------------
1 | # 2.11 极简模式执行 Python Shell
2 | 
3 |
4 | 在终端输入 Python 就会进入 Python Shell 。
5 |
6 | 方便是挺方便,就是有点说不出的难受,谁能告诉我,为什么要多出这么大一段无关的内容。
7 |
8 | 
9 |
10 | 这有点像,你上爱某艺看视频吧,都要先看个 90 秒的广告。
11 |
12 | 如果你和我一样不喜欢这种 『牛皮癣』,那么可以加个 `-q` 参数,静默进入 Python Shell,就像下面这样子,开启了极简模式,舒服多了。
13 |
14 | 
15 |
16 |
17 | 
18 |
19 |
20 |
--------------------------------------------------------------------------------
/source/c02/c02_11.rst:
--------------------------------------------------------------------------------
1 | 2.11 极简模式执行 Python Shell
2 | ==============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在终端输入 Python 就会进入 Python Shell 。
7 |
8 | 方便是挺方便,就是有点说不出的难受,谁能告诉我,为什么要多出这么大一段无关的内容。
9 |
10 | .. image:: http://image.iswbm.com/20200801202733.png
11 |
12 | 这有点像,你上爱某艺看视频吧,都要先看个 90 秒的广告。
13 |
14 | 如果你和我一样不喜欢这种 『牛皮癣』,那么可以加个 ``-q`` 参数,静默进入
15 | Python Shell,就像下面这样子,开启了极简模式,舒服多了。
16 |
17 | .. image:: http://image.iswbm.com/20200801203047.png
18 |
19 | .. image:: http://image.iswbm.com/20200512125643.png
20 |
--------------------------------------------------------------------------------
/source/c02/c02_12.md:
--------------------------------------------------------------------------------
1 | # 2.12 在执行任意代码前自动念一段平安经
2 | 
3 |
4 | 最近的"平安经"可谓是引起了不小的风波啊。
5 |
6 | 作为一个正儿八经的程序员,最害怕的就是自己的代码上线出现各种各样的 BUG。
7 |
8 | 为此明哥就研究了一下,如何在你执行任意 Python 代码前,让 Python 解释器自动念上一段平安经,保佑代码不出 BUG 。
9 |
10 | 没想到还真被我研究出来了
11 |
12 | 做好心理准备了嘛?
13 |
14 | 我要开始作妖了,噢不,是开始念经了。
15 |
16 | 
17 |
18 | 感谢佛祖保佑,Everything is ok,No bugs in the code.
19 |
20 |
21 |
22 | 你一定很想知道这是如何的吧?
23 |
24 | 如果你对 Linux 比较熟悉,就会知道,当你在使用 SSH 远程登陆 Linux 服务器的时候?会读取 `.bash_profile` 文件加载一些环境变量。
25 |
26 | `.bash_profile` 你可以视其为一个 shell 脚本,可以在这里写一些 shell 代码达到你的定制化需求。
27 |
28 | 而在 Python 中,也有类似 `.bash_profile` 的文件,这个文件一般情况下是不存在的。
29 |
30 | 我们需要新建一个用户环境目录,这个目录比较长,不需要你死记硬背,使用 site 模块的方法就可以获取,然后使用 `mkdir -p` 命令创建它。
31 |
32 | 
33 |
34 | 在这个目录下,新建一个 `usercustomize.py` 文件,注意名字必须是这个,换成其他的可就识别不到啦。
35 |
36 | 这个 `usercustomize.py` 的内容如下(明哥注:佛祖只保佑几个 Python 的主要应用方向,毕竟咱是 Python 攻城狮嘛...)
37 |
38 | 
39 |
40 | 这个文件我放在了我的 github 上,点击[这里](https://github.com/iswbm/magic-python/blob/master/usercustomize.py)直达。
41 |
42 | 一切都完成后,无论你是使用 `python xxx.py` 执行脚本
43 |
44 | 
45 |
46 | 还是使用 `python` 进入 Python Shell ,都会先念一下平安经保平安。
47 |
48 | 
49 |
50 | 另外,有读者反馈这种设置会导致在Win10环境下 VSCode不能正常识别已安装的Python环境,并报出代码有导包错误等问题,因此请在你知道你自己在做什么,会千万什么后果,否则请在体验后还原你的环境。
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/source/c02/c02_12.rst:
--------------------------------------------------------------------------------
1 | 2.12 在执行任意代码前自动念一段平安经
2 | =====================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 最近的”平安经”可谓是引起了不小的风波啊。
7 |
8 | 作为一个正儿八经的程序员,最害怕的就是自己的代码上线出现各种各样的 BUG。
9 |
10 | 为此明哥就研究了一下,如何在你执行任意 Python 代码前,让 Python
11 | 解释器自动念上一段平安经,保佑代码不出 BUG 。
12 |
13 | 没想到还真被我研究出来了
14 |
15 | 做好心理准备了嘛?
16 |
17 | 我要开始作妖了,噢不,是开始念经了。
18 |
19 | .. image:: http://image.iswbm.com/20200801221705.png
20 |
21 | 感谢佛祖保佑,Everything is ok,No bugs in the code.
22 |
23 | 你一定很想知道这是如何的吧?
24 |
25 | 如果你对 Linux 比较熟悉,就会知道,当你在使用 SSH 远程登陆 Linux
26 | 服务器的时候?会读取 ``.bash_profile`` 文件加载一些环境变量。
27 |
28 | ``.bash_profile`` 你可以视其为一个 shell 脚本,可以在这里写一些 shell
29 | 代码达到你的定制化需求。
30 |
31 | 而在 Python 中,也有类似 ``.bash_profile``
32 | 的文件,这个文件一般情况下是不存在的。
33 |
34 | 我们需要新建一个用户环境目录,这个目录比较长,不需要你死记硬背,使用
35 | site 模块的方法就可以获取,然后使用 ``mkdir -p`` 命令创建它。
36 |
37 | .. image:: http://image.iswbm.com/20200801220819.png
38 |
39 | 在这个目录下,新建一个 ``usercustomize.py``
40 | 文件,注意名字必须是这个,换成其他的可就识别不到啦。
41 |
42 | 这个 ``usercustomize.py`` 的内容如下(明哥注:佛祖只保佑几个 Python
43 | 的主要应用方向,毕竟咱是 Python 攻城狮嘛…)
44 |
45 | .. image:: http://image.iswbm.com/20200801221413.png
46 |
47 | 这个文件我放在了我的 github
48 | 上,点击\ `这里 `__\ 直达。
49 |
50 | 一切都完成后,无论你是使用 ``python xxx.py`` 执行脚本
51 |
52 | .. image:: http://image.iswbm.com/20200801221705.png
53 |
54 | 还是使用 ``python`` 进入 Python Shell ,都会先念一下平安经保平安。
55 |
56 | .. image:: http://image.iswbm.com/20200801221457.png
57 |
58 | 另外,有读者反馈这种设置会导致在Win10环境下
59 | VSCode不能正常识别已安装的Python环境,并报出代码有导包错误等问题,因此请在你知道你自己在做什么,会千万什么后果,否则请在体验后还原你的环境。
60 |
--------------------------------------------------------------------------------
/source/c02/c02_13.md:
--------------------------------------------------------------------------------
1 | # 2.13 启动 Python Shell 前自动执行某脚本
2 | 
3 |
4 | 前一节我们介绍了一种,只要运行解释器就会自动触发执行 Python 脚本的方法。
5 |
6 | 除此之外,可还有其他方法呢?
7 |
8 | 当然是有,只不过相对来说,会麻烦一点了。
9 |
10 | 先来看一下效果,在 `~/Library/Python/3.9/lib/python/site-packages` 目录下并没有 `usercustomize.py` 文件,但是在执行 python 进入 Python Shell 模式后,还是会打印平安经。
11 |
12 | 
13 |
14 | 这是如何做到的呢?
15 |
16 | 很简单,只要做两件事
17 |
18 | 第一件事,在任意你喜欢的目录下,新建 一个Python 脚本,名字也随意,比如我叫 `startup.py`,内容还是和上面一样
19 |
20 | 
21 |
22 | 第二件事,设置一个环境变量 PYTHONSTARTUP,指向你的脚本路径
23 |
24 | ```shell
25 | $ export PYTHONSTARTUP=/Users/MING/startup.py
26 | ```
27 |
28 | 这样就可以了。
29 |
30 | 但是这种方法只适用于 Python Shell ,并不适用于 Python 执行脚本的方法。
31 |
32 | 
33 |
34 | 如果要在脚本中实现这种效果,我目前想到最粗糙我笨拙的方法了 -- `手动加载执行`
35 |
36 | 
37 |
38 |
39 |
--------------------------------------------------------------------------------
/source/c02/c02_13.rst:
--------------------------------------------------------------------------------
1 | 2.13 启动 Python Shell 前自动执行某脚本
2 | =======================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 前一节我们介绍了一种,只要运行解释器就会自动触发执行 Python 脚本的方法。
7 |
8 | 除此之外,可还有其他方法呢?
9 |
10 | 当然是有,只不过相对来说,会麻烦一点了。
11 |
12 | 先来看一下效果,在 ``~/Library/Python/3.9/lib/python/site-packages``
13 | 目录下并没有 ``usercustomize.py`` 文件,但是在执行 python 进入 Python
14 | Shell 模式后,还是会打印平安经。
15 |
16 | .. image:: http://image.iswbm.com/20200801225652.png
17 |
18 | 这是如何做到的呢?
19 |
20 | 很简单,只要做两件事
21 |
22 | 第一件事,在任意你喜欢的目录下,新建 一个Python
23 | 脚本,名字也随意,比如我叫 ``startup.py``\ ,内容还是和上面一样
24 |
25 | .. image:: http://image.iswbm.com/20200801221413.png
26 |
27 | 第二件事,设置一个环境变量 PYTHONSTARTUP,指向你的脚本路径
28 |
29 | .. code:: shell
30 |
31 | $ export PYTHONSTARTUP=/Users/MING/startup.py
32 |
33 | 这样就可以了。
34 |
35 | 但是这种方法只适用于 Python Shell ,并不适用于 Python 执行脚本的方法。
36 |
37 | .. image:: http://image.iswbm.com/20200801230230.png
38 |
39 | 如果要在脚本中实现这种效果,我目前想到最粗糙我笨拙的方法了 –
40 | ``手动加载执行``
41 |
42 | .. image:: http://image.iswbm.com/20200801230503.png
43 |
--------------------------------------------------------------------------------
/source/c02/c02_15.md:
--------------------------------------------------------------------------------
1 | # 2.15 命令行式打开 idle 编辑脚本
2 |
3 | 
4 |
5 | 在你安装 Python 解释器的时候,会有一个选项,让你选择是否安装 idle,这是一个极简的 Python 编辑器,对于有点 python 编码的经验的同学,一般都已经安装了更加专业的代码编辑器,比如 pycharm,vscode 等,所以一般是不会去勾选它的。
6 |
7 | 但是对于第一次接触 Python 编程的初学者来说,在自己的电脑上,大概率是没有安装代码编辑器的,这时候有一个现成的编辑器,可以尽快的将 hello world 跑起来,是一件非常重要的事情,因此初学者一般会被建议安装 idle,这也是为什么 idle 是大多数人的第一个 Python 代码编辑器。
8 |
9 | 在你安装了 idle 后,如果你使用 Windows 电脑,点击 py 文件会有使用 idle 打开的选项,非常方便你直接编辑 py 文件。
10 |
11 | 但如若你在 mac 电脑上,你的右键,是没有这个选项的,那如何使用 idle 打开编辑呢?
12 |
13 | 可以在终端上使用如下这条命令即可调用 idle 打开指定文件
14 |
15 | ```shell
16 | python3 -m idlelib unshelve.py
17 | ```
18 |
19 | 使用的效果如下
20 |
21 | 
22 |
23 | 如果你不加文件的路径,默认会打开 idle 的 shell 模式
24 |
25 | 
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/source/c02/c02_15.rst:
--------------------------------------------------------------------------------
1 | 2.15 命令行式打开 idle 编辑脚本
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在你安装 Python 解释器的时候,会有一个选项,让你选择是否安装
7 | idle,这是一个极简的 Python 编辑器,对于有点 python
8 | 编码的经验的同学,一般都已经安装了更加专业的代码编辑器,比如
9 | pycharm,vscode 等,所以一般是不会去勾选它的。
10 |
11 | 但是对于第一次接触 Python
12 | 编程的初学者来说,在自己的电脑上,大概率是没有安装代码编辑器的,这时候有一个现成的编辑器,可以尽快的将
13 | hello world 跑起来,是一件非常重要的事情,因此初学者一般会被建议安装
14 | idle,这也是为什么 idle 是大多数人的第一个 Python 代码编辑器。
15 |
16 | 在你安装了 idle 后,如果你使用 Windows 电脑,点击 py 文件会有使用 idle
17 | 打开的选项,非常方便你直接编辑 py 文件。
18 |
19 | 但如若你在 mac 电脑上,你的右键,是没有这个选项的,那如何使用 idle
20 | 打开编辑呢?
21 |
22 | 可以在终端上使用如下这条命令即可调用 idle 打开指定文件
23 |
24 | .. code:: shell
25 |
26 | python3 -m idlelib unshelve.py
27 |
28 | 使用的效果如下
29 |
30 | .. image:: http://image.iswbm.com/20210504110446.png
31 |
32 | 如果你不加文件的路径,默认会打开 idle 的 shell 模式
33 |
34 | .. image:: http://image.iswbm.com/20210504110758.png
35 |
--------------------------------------------------------------------------------
/source/c02/c02_16.md:
--------------------------------------------------------------------------------
1 | # 2.16 快速计算字符串 base64编码
2 |
3 | 
4 |
5 | ## 对字符串编码和解码
6 |
7 | 对一个字符串进行 base64 编码 和 解码(加上 `-d` 参数即可)
8 |
9 | ```shell
10 | $ echo "hello, world" | python3 -m base64
11 | aGVsbG8sIHdvcmxkCg==
12 |
13 | $ echo "aGVsbG8sIHdvcmxkCg==" | python3 -m base64 -d
14 | hello, world
15 | ```
16 |
17 | 效果如下
18 |
19 | 
20 |
21 | ## 对文件进行编码和解码
22 |
23 | 在命令后面直接加文件的路径
24 |
25 | ```shell
26 | # 编码
27 | $ python3 -m base64 demo.py
28 | ZGVmIG1haW4oKToKICAgcHJpbnQoJ0hlbGxvIFdvcmxk8J+RjCcpCiAgIAppZiBfX25hbWVfXz09
29 | J19fbWFpbl9fJzoKICAgbWFpbigpCg==
30 |
31 | # 解码
32 | $ echo "ZGVmIG1haW4oKToKICAgcHJpbnQoJ0hlbGxvIFdvcmxk8J+RjCcpCiAgIAppZiBfX25hbWVfXz09
33 | J19fbWFpbl9fJzoKICAgbWFpbigpCg==" | python3 -m base64 -d
34 | def main():
35 | print('Hello World👌')
36 |
37 | if __name__=='__main__':
38 | main()
39 | ```
40 |
41 | 效果如下
42 |
43 | 
44 |
45 | 如果你的文件是 py 脚本的话,可以直接执行它
46 |
47 | 
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/source/c02/c02_16.rst:
--------------------------------------------------------------------------------
1 | 2.16 快速计算字符串 base64编码
2 | ==============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 对字符串编码和解码
7 | ------------------
8 |
9 | 对一个字符串进行 base64 编码 和 解码(加上 ``-d`` 参数即可)
10 |
11 | .. code:: shell
12 |
13 | $ echo "hello, world" | python3 -m base64
14 | aGVsbG8sIHdvcmxkCg==
15 |
16 | $ echo "aGVsbG8sIHdvcmxkCg==" | python3 -m base64 -d
17 | hello, world
18 |
19 | 效果如下
20 |
21 | .. image:: http://image.iswbm.com/20210504111702.png
22 |
23 | 对文件进行编码和解码
24 | --------------------
25 |
26 | 在命令后面直接加文件的路径
27 |
28 | .. code:: shell
29 |
30 | # 编码
31 | $ python3 -m base64 demo.py
32 | ZGVmIG1haW4oKToKICAgcHJpbnQoJ0hlbGxvIFdvcmxk8J+RjCcpCiAgIAppZiBfX25hbWVfXz09
33 | J19fbWFpbl9fJzoKICAgbWFpbigpCg==
34 |
35 | # 解码
36 | $ echo "ZGVmIG1haW4oKToKICAgcHJpbnQoJ0hlbGxvIFdvcmxk8J+RjCcpCiAgIAppZiBfX25hbWVfXz09
37 | J19fbWFpbl9fJzoKICAgbWFpbigpCg==" | python3 -m base64 -d
38 | def main():
39 | print('Hello World👌')
40 |
41 | if __name__=='__main__':
42 | main()
43 |
44 | 效果如下
45 |
46 | .. image:: http://image.iswbm.com/20210504112153.png
47 |
48 | 如果你的文件是 py 脚本的话,可以直接执行它
49 |
50 | .. image:: http://image.iswbm.com/20210504112257.png
51 |
--------------------------------------------------------------------------------
/source/c02/c02_17.md:
--------------------------------------------------------------------------------
1 | # 2.17 快速找到指定文件的mime类型
2 |
3 | 
4 |
5 | 识别 html 文件
6 |
7 | ```shell
8 | # 可在线检测
9 | $ python -m mimetypes https://docs.python.org/3/library/mimetypes.html
10 | type: text/html encoding: None
11 |
12 | # 也可离线检测(后面不再赘述)
13 | $ python -m mimetypes index.html
14 | type: text/html encoding: None
15 | ```
16 |
17 | 识别图片格式
18 |
19 | ```shell
20 | $ python -m mimetypes https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png
21 | type: image/png encoding: None
22 | ```
23 |
24 | 识别 Python 脚本
25 |
26 | ```shell
27 | $ python -m mimetypes sample.py
28 | type: text/x-python encoding: None # python文件
29 | ```
30 |
31 | 识别压缩文件
32 |
33 | ```shell
34 | $ python -m mimetypes sample.py.gz
35 | type: text/x-python encoding: gzip # python文件,gzip压缩
36 | ```
37 |
38 |
--------------------------------------------------------------------------------
/source/c02/c02_17.rst:
--------------------------------------------------------------------------------
1 | 2.17 快速找到指定文件的mime类型
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 识别 html 文件
7 |
8 | .. code:: shell
9 |
10 | # 可在线检测
11 | $ python -m mimetypes https://docs.python.org/3/library/mimetypes.html
12 | type: text/html encoding: None
13 |
14 | # 也可离线检测(后面不再赘述)
15 | $ python -m mimetypes index.html
16 | type: text/html encoding: None
17 |
18 | 识别图片格式
19 |
20 | .. code:: shell
21 |
22 | $ python -m mimetypes https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_272x92dp.png
23 | type: image/png encoding: None
24 |
25 | 识别 Python 脚本
26 |
27 | .. code:: shell
28 |
29 | $ python -m mimetypes sample.py
30 | type: text/x-python encoding: None # python文件
31 |
32 | 识别压缩文件
33 |
34 | .. code:: shell
35 |
36 | $ python -m mimetypes sample.py.gz
37 | type: text/x-python encoding: gzip # python文件,gzip压缩
38 |
--------------------------------------------------------------------------------
/source/c02/c02_18.md:
--------------------------------------------------------------------------------
1 | # 2.18 快速查看 Python 的环境信息
2 |
3 | 
4 |
5 | 所有与 Python 相关的信息与配置,你都可以使用下面这条命令将其全部打印出来
6 |
7 | ```shell
8 | $ python -m sysconfig
9 | ```
10 |
11 | 信息包括:
12 |
13 | - 你当前的操作系统平台
14 | - Python 的具体版本
15 | - 包的搜索路径
16 | - 以及各种环境变量
17 |
18 | 
19 |
20 |
--------------------------------------------------------------------------------
/source/c02/c02_18.rst:
--------------------------------------------------------------------------------
1 | 2.18 快速查看 Python 的环境信息
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 所有与 Python 相关的信息与配置,你都可以使用下面这条命令将其全部打印出来
7 |
8 | .. code:: shell
9 |
10 | $ python -m sysconfig
11 |
12 | 信息包括:
13 |
14 | - 你当前的操作系统平台
15 | - Python 的具体版本
16 | - 包的搜索路径
17 | - 以及各种环境变量
18 |
19 | .. image:: http://image.iswbm.com/20210504114516.png
20 |
--------------------------------------------------------------------------------
/source/c02/c02_19.md:
--------------------------------------------------------------------------------
1 | # 2.19 快速解压和压缩文件
2 |
3 | 
4 |
5 | ## tar 格式压缩包
6 |
7 | 创建一个 tar 压缩包
8 |
9 | ```shell
10 | # 将 demo 文件夹压缩成 demo.tar
11 | $ python3 -m tarfile -c demo.tar demo
12 | ```
13 |
14 | 解压 tar 压缩包
15 |
16 | ```shell
17 | # 解压 demo.tar 到 demo_new 文件夹下
18 | $ python3 -m tarfile -e demo.tar demo_new
19 | ```
20 |
21 | ## gzip 格式压缩包
22 |
23 | 创建一个 gzip 格式的压缩包(gzip 的输入,只能是一个文件,而不能是一个目录)
24 |
25 | ```shell
26 | $ ls -l | grep message
27 | -rw-r--r--@ 1 MING staff 97985 4 22 08:30 message
28 |
29 | # 将 message.html 文件夹压缩成 message.gz
30 | $ python3 -m gzip message
31 |
32 | $ ls -l | grep message
33 | -rw-r--r--@ 1 MING staff 97985 4 22 08:30 message
34 | -rw-r--r-- 1 MING staff 24908 5 4 12:49 message.gz
35 | ```
36 |
37 | 解压一个 gzip 格式的压缩包
38 |
39 | ```shell
40 | $ rm -rf message
41 |
42 | $ ls -l | grep message
43 | -rw-r--r-- 1 MING staff 87 5 4 12:51 message.gz
44 |
45 | # 解压 message.gz
46 | $ python3 -m gzip -d message.gz
47 |
48 | $ ls -l | grep message
49 | -rw-r--r-- 1 MING staff 62 5 4 12:52 message
50 | -rw-r--r-- 1 MING staff 87 5 4 12:51 message.gz
51 | ```
52 |
53 | ## zip 格式压缩包
54 |
55 | 创建一个 zip 格式的压缩包
56 |
57 | ```shell
58 | $ ls -l | grep demo
59 | drwxr-xr-x 3 MING staff 96 5 4 12:44 demo
60 |
61 | # 压缩 demo 文件夹为 demo.zip
62 | $ python3 -m zipfile -c demo.zip demo
63 |
64 | $ ls -l | grep demo
65 | drwxr-xr-x 3 MING staff 96 5 4 12:44 demo
66 | -rw-r--r-- 1 MING staff 74890 5 4 12:55 demo.zip
67 | ```
68 |
69 | 解压一个 zip 格式的压缩包
70 |
71 | ```shell
72 | $ rm -rf demo
73 |
74 | $ ls -l | grep demo
75 | -rw-r--r-- 1 MING staff 74890 5 4 12:55 demo.zip
76 |
77 | $ python3 -m zipfile -e demo.zip demo
78 |
79 | $ ls -l | grep demo
80 | drwxr-xr-x 3 MING staff 96 5 4 12:57 demo
81 | -rw-r--r-- 1 MING staff 74890 5 4 12:55 demo.zip
82 | ```
83 |
84 |
85 |
86 |
--------------------------------------------------------------------------------
/source/c02/c02_19.rst:
--------------------------------------------------------------------------------
1 | 2.19 快速解压和压缩文件
2 | =======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | tar 格式压缩包
7 | --------------
8 |
9 | 创建一个 tar 压缩包
10 |
11 | .. code:: shell
12 |
13 | # 将 demo 文件夹压缩成 demo.tar
14 | $ python3 -m tarfile -c demo.tar demo
15 |
16 | 解压 tar 压缩包
17 |
18 | .. code:: shell
19 |
20 | # 解压 demo.tar 到 demo_new 文件夹下
21 | $ python3 -m tarfile -e demo.tar demo_new
22 |
23 | gzip 格式压缩包
24 | ---------------
25 |
26 | 创建一个 gzip 格式的压缩包(gzip
27 | 的输入,只能是一个文件,而不能是一个目录)
28 |
29 | .. code:: shell
30 |
31 | $ ls -l | grep message
32 | -rw-r--r--@ 1 MING staff 97985 4 22 08:30 message
33 |
34 | # 将 message.html 文件夹压缩成 message.gz
35 | $ python3 -m gzip message
36 |
37 | $ ls -l | grep message
38 | -rw-r--r--@ 1 MING staff 97985 4 22 08:30 message
39 | -rw-r--r-- 1 MING staff 24908 5 4 12:49 message.gz
40 |
41 | 解压一个 gzip 格式的压缩包
42 |
43 | .. code:: shell
44 |
45 | $ rm -rf message
46 |
47 | $ ls -l | grep message
48 | -rw-r--r-- 1 MING staff 87 5 4 12:51 message.gz
49 |
50 | # 解压 message.gz
51 | $ python3 -m gzip -d message.gz
52 |
53 | $ ls -l | grep message
54 | -rw-r--r-- 1 MING staff 62 5 4 12:52 message
55 | -rw-r--r-- 1 MING staff 87 5 4 12:51 message.gz
56 |
57 | zip 格式压缩包
58 | --------------
59 |
60 | 创建一个 zip 格式的压缩包
61 |
62 | .. code:: shell
63 |
64 | $ ls -l | grep demo
65 | drwxr-xr-x 3 MING staff 96 5 4 12:44 demo
66 |
67 | # 压缩 demo 文件夹为 demo.zip
68 | $ python3 -m zipfile -c demo.zip demo
69 |
70 | $ ls -l | grep demo
71 | drwxr-xr-x 3 MING staff 96 5 4 12:44 demo
72 | -rw-r--r-- 1 MING staff 74890 5 4 12:55 demo.zip
73 |
74 | 解压一个 zip 格式的压缩包
75 |
76 | .. code:: shell
77 |
78 | $ rm -rf demo
79 |
80 | $ ls -l | grep demo
81 | -rw-r--r-- 1 MING staff 74890 5 4 12:55 demo.zip
82 |
83 | $ python3 -m zipfile -e demo.zip demo
84 |
85 | $ ls -l | grep demo
86 | drwxr-xr-x 3 MING staff 96 5 4 12:57 demo
87 | -rw-r--r-- 1 MING staff 74890 5 4 12:55 demo.zip
88 |
--------------------------------------------------------------------------------
/source/c02/c02_20.md:
--------------------------------------------------------------------------------
1 | # 2.20 快速编辑 Python 脚本
2 |
3 | 
4 |
5 | pyc是一种二进制文件,是由py文件经过编译后,生成的文件,是一种byte code,py文件变成pyc文件后,加载的速度会有所提高。因此在一些场景下,可以预先编译成 pyc 文件,来提高加载速度。
6 |
7 | 编译的命令非常的简单,示例如下
8 |
9 | ```shell
10 | $ tree demo
11 | demo
12 | └── main.py
13 |
14 | $ python3 -O -m compileall demo
15 | Listing 'demo'...
16 | Compiling 'demo/main.py'...
17 |
18 | $ tree demo
19 | demo
20 | ├── __pycache__
21 | │ └── main.cpython-39.opt-1.pyc
22 | └── main.py
23 | ```
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/source/c02/c02_20.rst:
--------------------------------------------------------------------------------
1 | 2.20 快速编辑 Python 脚本
2 | =========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | pyc是一种二进制文件,是由py文件经过编译后,生成的文件,是一种byte
7 | code,py文件变成pyc文件后,加载的速度会有所提高。因此在一些场景下,可以预先编译成
8 | pyc 文件,来提高加载速度。
9 |
10 | 编译的命令非常的简单,示例如下
11 |
12 | .. code:: shell
13 |
14 | $ tree demo
15 | demo
16 | └── main.py
17 |
18 | $ python3 -O -m compileall demo
19 | Listing 'demo'...
20 | Compiling 'demo/main.py'...
21 |
22 | $ tree demo
23 | demo
24 | ├── __pycache__
25 | │ └── main.cpython-39.opt-1.pyc
26 | └── main.py
27 |
--------------------------------------------------------------------------------
/source/c02/c02_21.md:
--------------------------------------------------------------------------------
1 | # 2.21 使用自带的 telnet 端口检测工具
2 |
3 | 
4 |
5 | 若你想检测指定的机器上有没有开放某端口,但本机并没有安装 telnet 工具,不如尝试一下 python 自带的 telnetlib 库,亦可实现你的需求。
6 |
7 | 检查 192.168.56.200 上的 22 端口有没有开放。
8 |
9 | ```shell
10 | $ python3 -m telnetlib -d 192.168.56.200 22
11 | Telnet(192.168.56.200,22): recv b'SSH-2.0-OpenSSH_7.4\r\n'
12 | SSH-2.0-OpenSSH_7.4
13 |
14 | Telnet(192.168.56.200,22): send b'\n'
15 | Telnet(192.168.56.200,22): recv b'Protocol mismatch.\n'
16 | Protocol mismatch.
17 | Telnet(192.168.56.200,22): recv b''
18 | *** Connection closed by remote host ***
19 | ```
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/source/c02/c02_21.rst:
--------------------------------------------------------------------------------
1 | 2.21 使用自带的 telnet 端口检测工具
2 | ===================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 若你想检测指定的机器上有没有开放某端口,但本机并没有安装 telnet
7 | 工具,不如尝试一下 python 自带的 telnetlib 库,亦可实现你的需求。
8 |
9 | 检查 192.168.56.200 上的 22 端口有没有开放。
10 |
11 | .. code:: shell
12 |
13 | $ python3 -m telnetlib -d 192.168.56.200 22
14 | Telnet(192.168.56.200,22): recv b'SSH-2.0-OpenSSH_7.4\r\n'
15 | SSH-2.0-OpenSSH_7.4
16 |
17 | Telnet(192.168.56.200,22): send b'\n'
18 | Telnet(192.168.56.200,22): recv b'Protocol mismatch.\n'
19 | Protocol mismatch.
20 | Telnet(192.168.56.200,22): recv b''
21 | *** Connection closed by remote host ***
22 |
--------------------------------------------------------------------------------
/source/c02/c02_22.md:
--------------------------------------------------------------------------------
1 | # 2.22 快速将项目打包成应用程序
2 |
3 | 
4 |
5 | 假设我当前有一个 demo 项目,目录结构树及相关文件的的代码如下
6 |
7 | 
8 |
9 | 现在我使用如下命令,将该项目进行打包,其中 demo 是项目的文件夹名,`main:main` 中的第一个 main 指的 `main.py`,而第二个 main 指的是 `main` 函数
10 |
11 | ```shell
12 | $ python3 -m zipapp demo -m "main:main"
13 | ```
14 |
15 | 执行完成后,会生成一个 `demo.pyz` 文件,可直接执行它。
16 |
17 | 具体演示过程如下
18 |
19 | 
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/source/c02/c02_22.rst:
--------------------------------------------------------------------------------
1 | 2.22 快速将项目打包成应用程序
2 | =============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 假设我当前有一个 demo 项目,目录结构树及相关文件的的代码如下
7 |
8 | .. image:: http://image.iswbm.com/20210504133550.png
9 |
10 | 现在我使用如下命令,将该项目进行打包,其中 demo
11 | 是项目的文件夹名,\ ``main:main`` 中的第一个 main 指的
12 | ``main.py``\ ,而第二个 main 指的是 ``main`` 函数
13 |
14 | .. code:: shell
15 |
16 | $ python3 -m zipapp demo -m "main:main"
17 |
18 | 执行完成后,会生成一个 ``demo.pyz`` 文件,可直接执行它。
19 |
20 | 具体演示过程如下
21 |
22 | .. image:: http://image.iswbm.com/20210504133711.png
23 |
--------------------------------------------------------------------------------
/source/c02/c02_23.md:
--------------------------------------------------------------------------------
1 | # 2.23 快速打印函数的调用栈
2 |
3 | 
4 |
5 | 在使用pdb时,手动打印调用栈
6 |
7 | ```python
8 | import traceback
9 | traceback.print_stack(file=sys.stdout)
10 | ```
11 |
12 | 或者直接使用 `where` (更简单的直接一个 `w`):https://www.codenong.com/1156023/
13 |
14 | ```python
15 | (Pdb) where
16 | /usr/lib/python2.7/site-packages/eventlet/greenpool.py(82)_spawn_n_impl()
17 | -> func(*args, **kwargs)
18 | /usr/lib/python2.7/site-packages/eventlet/wsgi.py(719)process_request()
19 | -> proto.__init__(sock, address, self)
20 | /usr/lib64/python2.7/SocketServer.py(649)__init__()
21 | -> self.handle()
22 | /usr/lib64/python2.7/BaseHTTPServer.py(340)handle()
23 | -> self.handle_one_request()
24 | /usr/lib/python2.7/site-packages/eventlet/wsgi.py(384)handle_one_request()
25 | -> self.handle_one_response()
26 | /usr/lib/python2.7/site-packages/eventlet/wsgi.py(481)handle_one_response()
27 | ```
28 |
29 |
--------------------------------------------------------------------------------
/source/c02/c02_23.rst:
--------------------------------------------------------------------------------
1 | 2.23 快速打印函数的调用栈
2 | =========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在使用pdb时,手动打印调用栈
7 |
8 | .. code:: python
9 |
10 | import traceback
11 | traceback.print_stack(file=sys.stdout)
12 |
13 | 或者直接使用 ``where`` (更简单的直接一个
14 | ``w``\ ):https://www.codenong.com/1156023/
15 |
16 | .. code:: python
17 |
18 | (Pdb) where
19 | /usr/lib/python2.7/site-packages/eventlet/greenpool.py(82)_spawn_n_impl()
20 | -> func(*args, **kwargs)
21 | /usr/lib/python2.7/site-packages/eventlet/wsgi.py(719)process_request()
22 | -> proto.__init__(sock, address, self)
23 | /usr/lib64/python2.7/SocketServer.py(649)__init__()
24 | -> self.handle()
25 | /usr/lib64/python2.7/BaseHTTPServer.py(340)handle()
26 | -> self.handle_one_request()
27 | /usr/lib/python2.7/site-packages/eventlet/wsgi.py(384)handle_one_request()
28 | -> self.handle_one_response()
29 | /usr/lib/python2.7/site-packages/eventlet/wsgi.py(481)handle_one_response()
30 |
--------------------------------------------------------------------------------
/source/c03/c03_11.md:
--------------------------------------------------------------------------------
1 | # 3.11 Python 读取文件的六种方式
2 |
3 | 
4 |
5 | ## 第一种:使用 open
6 |
7 | 常规操作
8 |
9 | ```python
10 | with open('data.txt') as fp:
11 | content = fp.readlines()
12 | ```
13 |
14 | ## 第二种:使用 fileinput
15 |
16 | 使用内置库 fileinput
17 |
18 | ```python
19 | import fileinput
20 |
21 | with fileinput.input(files=('data.txt',)) as file:
22 | content = [line for line in file]
23 | ```
24 |
25 | ## 第三种:使用 filecache
26 |
27 | 使用内置库 filecache,你可以用它来指定读取具体某一行,或者某几行,不指定就读取全部行。
28 |
29 | ```python
30 | import linecache
31 |
32 | content = linecache.getlines('werobot.toml')
33 | ```
34 |
35 | ## 第四种:使用 codecs
36 |
37 | 使用 `codecs.open` 来读取
38 |
39 | ```python
40 | import codecs
41 | file=codecs.open("README.md", 'r')
42 | file.read()
43 | ```
44 |
45 | 如果你还在使用 Python2,那么它可以帮你处理掉 Python 2 下写文件时一些编码错误,一般的建议是:
46 |
47 | - 在 Python 3 下写文件,直接使用 open
48 | - 在 Python 2 下写文件,推荐使用 codecs.open,特别是有中文的情况下
49 | - 如果希望代码同时兼容Python2和Python3,那么也推荐用codecs.open
50 |
51 | ## 第五种:使用 io 模块
52 |
53 | 使用 io 模块的 open 函数
54 |
55 | ```python
56 | import io
57 | file=io.open("README.md")
58 | file.read()
59 | ```
60 |
61 | 经朋友提醒,我才发现 io.open 和 open 是同一个函数
62 |
63 | ```python
64 | Python 3.9.2 (default, Feb 28 2021, 17:03:44)
65 | [GCC 10.2.1 20210110] on linux
66 | Type "help", "copyright", "credits" or "license" for more information.
67 | >>> import os
68 | >>> (open1:=open) is (open2:=os.open)
69 | False
70 | >>> import io
71 | >>> (open3:=open) is (open3:=io.open)
72 | True
73 | ```
74 |
75 | ## 第六种:使用 os 模块
76 |
77 | os 模块也自带了 open 函数,直接操作的是底层的 I/O 流,操作的时候是最麻烦的
78 |
79 | ```python
80 | >>> import os
81 | >>> fp = os.open("hello.txt", os.O_RDONLY)
82 | >>> os.read(fp, 12)
83 | b'hello, world'
84 | >>> os.close(fp)
85 | ```
86 |
87 |
88 |
89 |
--------------------------------------------------------------------------------
/source/c03/c03_11.rst:
--------------------------------------------------------------------------------
1 | 3.11 Python 读取文件的六种方式
2 | ==============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 第一种:使用 open
7 | -----------------
8 |
9 | 常规操作
10 |
11 | .. code:: python
12 |
13 | with open('data.txt') as fp:
14 | content = fp.readlines()
15 |
16 | 第二种:使用 fileinput
17 | ----------------------
18 |
19 | 使用内置库 fileinput
20 |
21 | .. code:: python
22 |
23 | import fileinput
24 |
25 | with fileinput.input(files=('data.txt',)) as file:
26 | content = [line for line in file]
27 |
28 | 第三种:使用 filecache
29 | ----------------------
30 |
31 | 使用内置库
32 | filecache,你可以用它来指定读取具体某一行,或者某几行,不指定就读取全部行。
33 |
34 | .. code:: python
35 |
36 | import linecache
37 |
38 | content = linecache.getlines('werobot.toml')
39 |
40 | 第四种:使用 codecs
41 | -------------------
42 |
43 | 使用 ``codecs.open`` 来读取
44 |
45 | .. code:: python
46 |
47 | import codecs
48 | file=codecs.open("README.md", 'r')
49 | file.read()
50 |
51 | 如果你还在使用 Python2,那么它可以帮你处理掉 Python 2
52 | 下写文件时一些编码错误,一般的建议是:
53 |
54 | - 在 Python 3 下写文件,直接使用 open
55 | - 在 Python 2 下写文件,推荐使用 codecs.open,特别是有中文的情况下
56 | - 如果希望代码同时兼容Python2和Python3,那么也推荐用codecs.open
57 |
58 | 第五种:使用 io 模块
59 | --------------------
60 |
61 | 使用 io 模块的 open 函数
62 |
63 | .. code:: python
64 |
65 | import io
66 | file=io.open("README.md")
67 | file.read()
68 |
69 | 经朋友提醒,我才发现 io.open 和 open 是同一个函数
70 |
71 | .. code:: python
72 |
73 | Python 3.9.2 (default, Feb 28 2021, 17:03:44)
74 | [GCC 10.2.1 20210110] on linux
75 | Type "help", "copyright", "credits" or "license" for more information.
76 | >>> import os
77 | >>> (open1:=open) is (open2:=os.open)
78 | False
79 | >>> import io
80 | >>> (open3:=open) is (open3:=io.open)
81 | True
82 |
83 | 第六种:使用 os 模块
84 | --------------------
85 |
86 | os 模块也自带了 open 函数,直接操作的是底层的 I/O
87 | 流,操作的时候是最麻烦的
88 |
89 | .. code:: python
90 |
91 | >>> import os
92 | >>> fp = os.open("hello.txt", os.O_RDONLY)
93 | >>> os.read(fp, 12)
94 | b'hello, world'
95 | >>> os.close(fp)
96 |
--------------------------------------------------------------------------------
/source/c03/c03_13.md:
--------------------------------------------------------------------------------
1 | # 3.13 创造 "新语法" 的黑科技
2 |
3 | 
4 |
5 | 通常我们遍历一个元素为 5-10 的数组,会这么写
6 |
7 | ```python
8 | >>> for i in range(5,11):
9 | ... print(i)
10 | ...
11 | 5
12 | 6
13 | 7
14 | 8
15 | 9
16 | 10
17 | ```
18 |
19 | 写法虽然简单,但总有一种不够直观的样子。
20 |
21 | 今天介绍一个黑科技方法,可以让这种写法更加直观,不够请谨慎使用,因为这个方法有点 "逆天",会让人误以为是 Python 又出了什么新语法。
22 |
23 | 最后的效果是这样子的。
24 |
25 | ```python
26 | >>> for i in 5|到|10:
27 | ... print(i)
28 | ...
29 | 5
30 | 6
31 | 7
32 | 8
33 | 9
34 | ```
35 |
36 | `|到|` 很容易让人误以为是什么新的语法?
37 |
38 | 其实不是的,`|到|` 应该分为 `|` 、`到`、`|` 这三个部分,下面我们一一讲解。
39 |
40 | 第一和第三的 `|` 是同个意思,它就是一个普通的运算符,通常我们使用 `or` 关键字来替代它,导致很多人对这个符号比较陌生。
41 |
42 | 这边是一个简单的例子,当两边 `|` 两边有一边为 True 就会返回 True
43 |
44 | ``` python
45 | >>> if True | False:
46 | ... print("ok")
47 | ...
48 | ok
49 | >>>
50 | >>> if False | False:
51 | ... print("ok")
52 | ...
53 | >>>
54 | ```
55 |
56 | 基本上所有的运算符都可以通过魔法方法来重新定义运算符的逻辑,这个过程叫做运算符重载, `|` 也不例外。
57 |
58 | 控制 `|` 的魔法方法是 `__or__` 和 `__xor__`
59 |
60 | 讲完了第一个和第三个字符,现在说说第二个字符 `到`
61 |
62 | `到` 实际上是一个类的实例,上面为了神秘,我没有事先给出完整代码
63 |
64 | 定义一个 Magic 的类,用于改变 range 的 `|` 方法
65 |
66 | ```python
67 | >>> class Magic(object):
68 | ... def __init__(self, func):
69 | ... self.func = func
70 | ... def __or__(self, other):
71 | ... return self.func(other)
72 | ... def __ror__(self, other):
73 | ... self.func = partial(self.func, other)
74 | ... return self
75 | ...
76 | >>>
77 | >>> 到 = Magic(range)
78 | ```
79 |
80 | 总结一下,这三者如何起作用的?
81 |
82 | - `到` 是 Magic 类的一个实例
83 | - `__or__` 定义的是 `到` 实例右侧遇到 `|` 的行为
84 | - `__xor__` 定义的是 `到` 实例左侧遇到 `|` 的行为
85 |
86 |
--------------------------------------------------------------------------------
/source/c03/c03_13.rst:
--------------------------------------------------------------------------------
1 | 3.13 创造 “新语法” 的黑科技
2 | ===========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 通常我们遍历一个元素为 5-10 的数组,会这么写
7 |
8 | .. code:: python
9 |
10 | >>> for i in range(5,11):
11 | ... print(i)
12 | ...
13 | 5
14 | 6
15 | 7
16 | 8
17 | 9
18 | 10
19 |
20 | 写法虽然简单,但总有一种不够直观的样子。
21 |
22 | 今天介绍一个黑科技方法,可以让这种写法更加直观,不够请谨慎使用,因为这个方法有点
23 | “逆天”,会让人误以为是 Python 又出了什么新语法。
24 |
25 | 最后的效果是这样子的。
26 |
27 | .. code:: python
28 |
29 | >>> for i in 5|到|10:
30 | ... print(i)
31 | ...
32 | 5
33 | 6
34 | 7
35 | 8
36 | 9
37 |
38 | ``|到|`` 很容易让人误以为是什么新的语法?
39 |
40 | 其实不是的,\ ``|到|`` 应该分为 ``|`` 、\ ``到``\ 、\ ``|``
41 | 这三个部分,下面我们一一讲解。
42 |
43 | 第一和第三的 ``|`` 是同个意思,它就是一个普通的运算符,通常我们使用
44 | ``or`` 关键字来替代它,导致很多人对这个符号比较陌生。
45 |
46 | 这边是一个简单的例子,当两边 ``|`` 两边有一边为 True 就会返回 True
47 |
48 | .. code:: python
49 |
50 | >>> if True | False:
51 | ... print("ok")
52 | ...
53 | ok
54 | >>>
55 | >>> if False | False:
56 | ... print("ok")
57 | ...
58 | >>>
59 |
60 | 基本上所有的运算符都可以通过魔法方法来重新定义运算符的逻辑,这个过程叫做运算符重载,
61 | ``|`` 也不例外。
62 |
63 | 控制 ``|`` 的魔法方法是 ``__or__`` 和 ``__xor__``
64 |
65 | 讲完了第一个和第三个字符,现在说说第二个字符 ``到``
66 |
67 | ``到`` 实际上是一个类的实例,上面为了神秘,我没有事先给出完整代码
68 |
69 | 定义一个 Magic 的类,用于改变 range 的 ``|`` 方法
70 |
71 | .. code:: python
72 |
73 | >>> class Magic(object):
74 | ... def __init__(self, func):
75 | ... self.func = func
76 | ... def __or__(self, other):
77 | ... return self.func(other)
78 | ... def __ror__(self, other):
79 | ... self.func = partial(self.func, other)
80 | ... return self
81 | ...
82 | >>>
83 | >>> 到 = Magic(range)
84 |
85 | 总结一下,这三者如何起作用的?
86 |
87 | - ``到`` 是 Magic 类的一个实例
88 | - ``__or__`` 定义的是 ``到`` 实例右侧遇到 ``|`` 的行为
89 | - ``__xor__`` 定义的是 ``到`` 实例左侧遇到 ``|`` 的行为
90 |
--------------------------------------------------------------------------------
/source/c05/c05_01.md:
--------------------------------------------------------------------------------
1 | # 5.1 嵌套上下文管理的另类写法
2 | 
3 |
4 | 当我们要写一个嵌套的上下文管理器时,可能会这样写
5 |
6 | ```python
7 | import contextlib
8 |
9 | @contextlib.contextmanager
10 | def test_context(name):
11 | print('enter, my name is {}'.format(name))
12 |
13 | yield
14 |
15 | print('exit, my name is {}'.format(name))
16 |
17 | with test_context('aaa'):
18 | with test_context('bbb'):
19 | print('========== in main ============')
20 | ```
21 |
22 | 输出结果如下
23 |
24 | ```python
25 | enter, my name is aaa
26 | enter, my name is bbb
27 | ========== in main ============
28 | exit, my name is bbb
29 | exit, my name is aaa
30 | ```
31 |
32 | 除此之外,你可知道,还有另一种嵌套写法
33 |
34 | ```python
35 | with test_context('aaa'), test_context('bbb'):
36 | print('========== in main ============')
37 | ```
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/source/c05/c05_01.rst:
--------------------------------------------------------------------------------
1 | 5.1 嵌套上下文管理的另类写法
2 | ============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当我们要写一个嵌套的上下文管理器时,可能会这样写
7 |
8 | .. code:: python
9 |
10 | import contextlib
11 |
12 | @contextlib.contextmanager
13 | def test_context(name):
14 | print('enter, my name is {}'.format(name))
15 |
16 | yield
17 |
18 | print('exit, my name is {}'.format(name))
19 |
20 | with test_context('aaa'):
21 | with test_context('bbb'):
22 | print('========== in main ============')
23 |
24 | 输出结果如下
25 |
26 | .. code:: python
27 |
28 | enter, my name is aaa
29 | enter, my name is bbb
30 | ========== in main ============
31 | exit, my name is bbb
32 | exit, my name is aaa
33 |
34 | 除此之外,你可知道,还有另一种嵌套写法
35 |
36 | .. code:: python
37 |
38 | with test_context('aaa'), test_context('bbb'):
39 | print('========== in main ============')
40 |
--------------------------------------------------------------------------------
/source/c05/c05_02.md:
--------------------------------------------------------------------------------
1 | # 5.2 将嵌套 for 循环写成单行
2 | 
3 |
4 | 我们经常会写如下这种嵌套的 for 循环代码
5 |
6 | ```python
7 | list1 = range(1,3)
8 | list2 = range(4,6)
9 | list3 = range(7,9)
10 | for item1 in list1:
11 | for item2 in list2:
12 | for item3 in list3:
13 | print(item1+item2+item3)
14 | ```
15 |
16 | 这里仅仅是三个 for 循环,在实际编码中,有可能会有更多层。
17 |
18 | 这样的代码,可读性非常的差,很多人不想这么写,可又没有更好的写法。
19 |
20 | 这里介绍一种我常用的写法,使用 itertools 这个库来实现更优雅易读的代码。
21 |
22 | ```python
23 | from itertools import product
24 | list1 = range(1,3)
25 | list2 = range(4,6)
26 | list3 = range(7,9)
27 | for item1,item2,item3 in product(list1, list2, list3):
28 | print(item1+item2+item3)
29 | ```
30 |
31 | 输出如下
32 |
33 | ```shell
34 | $ python demo.py
35 | 12
36 | 13
37 | 13
38 | 14
39 | 13
40 | 14
41 | 14
42 | 15
43 | ```
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/source/c05/c05_02.rst:
--------------------------------------------------------------------------------
1 | 5.2 将嵌套 for 循环写成单行
2 | ===========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 我们经常会写如下这种嵌套的 for 循环代码
7 |
8 | .. code:: python
9 |
10 | list1 = range(1,3)
11 | list2 = range(4,6)
12 | list3 = range(7,9)
13 | for item1 in list1:
14 | for item2 in list2:
15 | for item3 in list3:
16 | print(item1+item2+item3)
17 |
18 | 这里仅仅是三个 for 循环,在实际编码中,有可能会有更多层。
19 |
20 | 这样的代码,可读性非常的差,很多人不想这么写,可又没有更好的写法。
21 |
22 | 这里介绍一种我常用的写法,使用 itertools 这个库来实现更优雅易读的代码。
23 |
24 | .. code:: python
25 |
26 | from itertools import product
27 | list1 = range(1,3)
28 | list2 = range(4,6)
29 | list3 = range(7,9)
30 | for item1,item2,item3 in product(list1, list2, list3):
31 | print(item1+item2+item3)
32 |
33 | 输出如下
34 |
35 | .. code:: shell
36 |
37 | $ python demo.py
38 | 12
39 | 13
40 | 13
41 | 14
42 | 13
43 | 14
44 | 14
45 | 15
46 |
--------------------------------------------------------------------------------
/source/c05/c05_03.md:
--------------------------------------------------------------------------------
1 | # 5.3 单行实现 for 死循环如何写?
2 | 
3 |
4 | 如果让你在不借助 while ,只使用 for 来写一个死循环?
5 |
6 | **你会写吗?**
7 |
8 | **如果你还说简单,你可以自己试一下。**
9 |
10 | ...
11 |
12 | 如果你尝试后,仍然写不出来,那我给出自己的做法。
13 |
14 | ```python
15 | for i in iter(int, 1):pass
16 | ```
17 |
18 |
19 |
20 | **是不是傻了?iter 还有这种用法?这为啥是个死循环?**
21 |
22 | 关于这个问题,你如果看中文网站,可能找不到相关资料。
23 |
24 | 还好你可以通过 IDE 看py源码里的注释内容,介绍了很详细的使用方法。
25 |
26 | 原来iter有两种使用方法。
27 |
28 | - 通常我们的认知是第一种,将一个列表转化为一个迭代器。
29 |
30 | - 而第二种方法,他接收一个 callable对象,和一个sentinel 参数。第一个对象会一直运行,直到它返回 sentinel 值才结束。
31 |
32 | 那`int` 呢?
33 |
34 | 这又是一个知识点,int 是一个内建方法。通过看注释,可以看出它是有默认值0的。你可以在console 模式下输入 `int()` 看看是不是返回0。
35 |
36 | 由于int() 永远返回0,永远返回不了1,所以这个 for 循环会没有终点。一直运行下去。
37 |
38 |
39 |
--------------------------------------------------------------------------------
/source/c05/c05_03.rst:
--------------------------------------------------------------------------------
1 | 5.3 单行实现 for 死循环如何写?
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 如果让你在不借助 while ,只使用 for 来写一个死循环?
7 |
8 | **你会写吗?**
9 |
10 | **如果你还说简单,你可以自己试一下。**
11 |
12 | …
13 |
14 | 如果你尝试后,仍然写不出来,那我给出自己的做法。
15 |
16 | .. code:: python
17 |
18 | for i in iter(int, 1):pass
19 |
20 | **是不是傻了?iter 还有这种用法?这为啥是个死循环?**
21 |
22 | 关于这个问题,你如果看中文网站,可能找不到相关资料。
23 |
24 | 还好你可以通过 IDE 看py源码里的注释内容,介绍了很详细的使用方法。
25 |
26 | 原来iter有两种使用方法。
27 |
28 | - 通常我们的认知是第一种,将一个列表转化为一个迭代器。
29 |
30 | - 而第二种方法,他接收一个 callable对象,和一个sentinel
31 | 参数。第一个对象会一直运行,直到它返回 sentinel 值才结束。
32 |
33 | 那\ ``int`` 呢?
34 |
35 | 这又是一个知识点,int
36 | 是一个内建方法。通过看注释,可以看出它是有默认值0的。你可以在console
37 | 模式下输入 ``int()`` 看看是不是返回0。
38 |
39 | 由于int() 永远返回0,永远返回不了1,所以这个 for
40 | 循环会没有终点。一直运行下去。
41 |
--------------------------------------------------------------------------------
/source/c05/c05_04.md:
--------------------------------------------------------------------------------
1 | # 5.4 如何关闭异常自动关联上下文?
2 | 
3 |
4 | 当你在处理异常时,由于处理不当或者其他问题,再次抛出另一个异常时,往外抛出的异常也会携带原始的异常信息。
5 |
6 | 就像这样子。
7 |
8 | ```python
9 | try:
10 | print(1 / 0)
11 | except Exception as exc:
12 | raise RuntimeError("Something bad happened")
13 | ```
14 |
15 | 从输出可以看到两个异常信息
16 |
17 | ```python
18 | Traceback (most recent call last):
19 | File "demo.py", line 2, in
20 | print(1 / 0)
21 | ZeroDivisionError: division by zero
22 |
23 | During handling of the above exception, another exception occurred:
24 |
25 | Traceback (most recent call last):
26 | File "demo.py", line 4, in
27 | raise RuntimeError("Something bad happened")
28 | RuntimeError: Something bad happened
29 | ```
30 |
31 | 如果在异常处理程序或 finally 块中引发异常,默认情况下,异常机制会隐式工作会将先前的异常附加为新异常的 `__context__`属性。这就是 Python 默认开启的自动关联异常上下文。
32 |
33 | 如果你想自己控制这个上下文,可以加个 from 关键字(`from` 语法会有个限制,就是第二个表达式必须是另一个异常类或实例。),来表明你的新异常是直接由哪个异常引起的。
34 |
35 | ```python
36 | try:
37 | print(1 / 0)
38 | except Exception as exc:
39 | raise RuntimeError("Something bad happened") from exc
40 | ```
41 |
42 | 输出如下
43 |
44 | ```python
45 | Traceback (most recent call last):
46 | File "demo.py", line 2, in
47 | print(1 / 0)
48 | ZeroDivisionError: division by zero
49 |
50 | The above exception was the direct cause of the following exception:
51 |
52 | Traceback (most recent call last):
53 | File "demo.py", line 4, in
54 | raise RuntimeError("Something bad happened") from exc
55 | RuntimeError: Something bad happened
56 | ```
57 |
58 |
59 |
60 | 当然,你也可以通过`with_traceback()`方法为异常设置上下文`__context__`属性,这也能在`traceback`更好地显示异常信息。
61 |
62 | ```python
63 | try:
64 | print(1 / 0)
65 | except Exception as exc:
66 | raise RuntimeError("bad thing").with_traceback(exc)
67 | ```
68 |
69 |
70 |
71 | 最后,如果我想彻底关闭这个自动关联异常上下文的机制?有什么办法呢?
72 |
73 | 可以使用 `raise...from None`,从下面的例子上看,已经没有了原始异常
74 |
75 | ```python
76 | $ cat demo.py
77 | try:
78 | print(1 / 0)
79 | except Exception as exc:
80 | raise RuntimeError("Something bad happened") from None
81 | $
82 | $ python demo.py
83 | Traceback (most recent call last):
84 | File "demo.py", line 4, in
85 | raise RuntimeError("Something bad happened") from None
86 | RuntimeError: Something bad happened
87 | (PythonCodingTime)
88 | ```
89 |
90 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/source/c05/c05_05.md:
--------------------------------------------------------------------------------
1 | # 5.5 自带的缓存机制不用白不用
2 | 
3 |
4 | 缓存是一种将定量数据加以保存,以备迎合后续获取需求的处理方式,旨在加快数据获取的速度。
5 |
6 | 数据的生成过程可能需要经过计算,规整,远程获取等操作,如果是同一份数据需要多次使用,每次都重新生成会大大浪费时间。所以,如果将计算或者远程请求等操作获得的数据缓存下来,会加快后续的数据获取需求。
7 |
8 | 为了实现这个需求,Python 3.2 + 中给我们提供了一个机制,可以很方便地实现,而不需要你去写这样的逻辑代码。
9 |
10 | 这个机制实现于 functool 模块中的 lru_cache 装饰器。
11 |
12 | ```python
13 | @functools.lru_cache(maxsize=None, typed=False)
14 | ```
15 |
16 | 参数解读:
17 |
18 | - maxsize:最多可以缓存多少个此函数的调用结果,如果为None,则无限制,设置为 2 的幂时,性能最佳
19 | - typed:若为 True,则不同参数类型的调用将分别缓存。
20 |
21 | 举个例子
22 |
23 | ```python
24 | from functools import lru_cache
25 |
26 | @lru_cache(None)
27 | def add(x, y):
28 | print("calculating: %s + %s" % (x, y))
29 | return x + y
30 |
31 | print(add(1, 2))
32 | print(add(1, 2))
33 | print(add(2, 3))
34 | ```
35 |
36 | 输出如下,可以看到第二次调用并没有真正地执行函数体,而是直接返回缓存里的结果
37 |
38 | ```shell
39 | calculating: 1 + 2
40 | 3
41 | 3
42 | calculating: 2 + 3
43 | 5
44 | ```
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/source/c05/c05_05.rst:
--------------------------------------------------------------------------------
1 | 5.5 自带的缓存机制不用白不用
2 | ============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 缓存是一种将定量数据加以保存,以备迎合后续获取需求的处理方式,旨在加快数据获取的速度。
7 |
8 | 数据的生成过程可能需要经过计算,规整,远程获取等操作,如果是同一份数据需要多次使用,每次都重新生成会大大浪费时间。所以,如果将计算或者远程请求等操作获得的数据缓存下来,会加快后续的数据获取需求。
9 |
10 | 为了实现这个需求,Python 3.2 +
11 | 中给我们提供了一个机制,可以很方便地实现,而不需要你去写这样的逻辑代码。
12 |
13 | 这个机制实现于 functool 模块中的 lru_cache 装饰器。
14 |
15 | .. code:: python
16 |
17 | @functools.lru_cache(maxsize=None, typed=False)
18 |
19 | 参数解读:
20 |
21 | - maxsize:最多可以缓存多少个此函数的调用结果,如果为None,则无限制,设置为
22 | 2 的幂时,性能最佳
23 | - typed:若为 True,则不同参数类型的调用将分别缓存。
24 |
25 | 举个例子
26 |
27 | .. code:: python
28 |
29 | from functools import lru_cache
30 |
31 | @lru_cache(None)
32 | def add(x, y):
33 | print("calculating: %s + %s" % (x, y))
34 | return x + y
35 |
36 | print(add(1, 2))
37 | print(add(1, 2))
38 | print(add(2, 3))
39 |
40 | 输出如下,可以看到第二次调用并没有真正地执行函数体,而是直接返回缓存里的结果
41 |
42 | .. code:: shell
43 |
44 | calculating: 1 + 2
45 | 3
46 | 3
47 | calculating: 2 + 3
48 | 5
49 |
--------------------------------------------------------------------------------
/source/c05/c05_06.md:
--------------------------------------------------------------------------------
1 | # 5.6 如何流式读取数G超大文件
2 | 
3 |
4 | 使用 with...open... 可以从一个文件中读取数据,这是所有 Python 开发者都非常熟悉的操作。
5 |
6 | 但是如果你使用不当,也会带来很大的麻烦。
7 |
8 | 比如当你使用了 read 函数,其实 Python 会将文件的内容一次性地全部载入内存中,如果文件有 10 个G甚至更多,那么你的电脑就要消耗的内存非常巨大。
9 |
10 | ```python
11 | # 一次性读取
12 | with open("big_file.txt", "r") as fp:
13 | content = fp.read()
14 | ```
15 |
16 | 对于这个问题,你也许会想到使用 readline 去做一个生成器来逐行返回。
17 |
18 | ```python
19 | def read_from_file(filename):
20 | with open(filename, "r") as fp:
21 | yield fp.readline()
22 | ```
23 |
24 | 可如果这个文件内容就一行呢,一行就 10个G,其实你还是会一次性读取全部内容。
25 |
26 | 最优雅的解决方法是,在使用 read 方法时,指定每次只读取固定大小的内容,比如下面的代码中,每次只读取 8kb 返回。
27 |
28 | ```python
29 | def read_from_file(filename, block_size = 1024 * 8):
30 | with open(filename, "r") as fp:
31 | while True:
32 | chunk = fp.read(block_size)
33 | if not chunk:
34 | break
35 |
36 | yield chunk
37 | ```
38 |
39 | 上面的代码,功能上已经没有问题了,但是代码看起来还是有些臃肿。
40 |
41 | 借助偏函数 和 iter 函数可以优化一下代码
42 |
43 | ```python
44 | from functools import partial
45 |
46 | def read_from_file(filename, block_size = 1024 * 8):
47 | with open(filename, "r") as fp:
48 | for chunk in iter(partial(fp.read, block_size), ""):
49 | yield chunk
50 | ```
51 |
52 | 如果你使用的是 Python 3.8 +,还有一种更直观、易于理解的写法,既不用使用偏函数,也不用掌握 iter 这种另类的用法。而只要用利用 海象运算符就可以,具体代码如下
53 |
54 | ```python
55 | def read_from_file(filename, block_size = 1024 * 8):
56 | with open(filename, "r") as fp:
57 | while chunk := fp.read(block_size):
58 | yield chunk
59 | ```
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/source/c05/c05_06.rst:
--------------------------------------------------------------------------------
1 | 5.6 如何流式读取数G超大文件
2 | ===========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 使用 with…open… 可以从一个文件中读取数据,这是所有 Python
7 | 开发者都非常熟悉的操作。
8 |
9 | 但是如果你使用不当,也会带来很大的麻烦。
10 |
11 | 比如当你使用了 read 函数,其实 Python
12 | 会将文件的内容一次性地全部载入内存中,如果文件有 10
13 | 个G甚至更多,那么你的电脑就要消耗的内存非常巨大。
14 |
15 | .. code:: python
16 |
17 | # 一次性读取
18 | with open("big_file.txt", "r") as fp:
19 | content = fp.read()
20 |
21 | 对于这个问题,你也许会想到使用 readline 去做一个生成器来逐行返回。
22 |
23 | .. code:: python
24 |
25 | def read_from_file(filename):
26 | with open(filename, "r") as fp:
27 | yield fp.readline()
28 |
29 | 可如果这个文件内容就一行呢,一行就
30 | 10个G,其实你还是会一次性读取全部内容。
31 |
32 | 最优雅的解决方法是,在使用 read
33 | 方法时,指定每次只读取固定大小的内容,比如下面的代码中,每次只读取 8kb
34 | 返回。
35 |
36 | .. code:: python
37 |
38 | def read_from_file(filename, block_size = 1024 * 8):
39 | with open(filename, "r") as fp:
40 | while True:
41 | chunk = fp.read(block_size)
42 | if not chunk:
43 | break
44 |
45 | yield chunk
46 |
47 | 上面的代码,功能上已经没有问题了,但是代码看起来还是有些臃肿。
48 |
49 | 借助偏函数 和 iter 函数可以优化一下代码
50 |
51 | .. code:: python
52 |
53 | from functools import partial
54 |
55 | def read_from_file(filename, block_size = 1024 * 8):
56 | with open(filename, "r") as fp:
57 | for chunk in iter(partial(fp.read, block_size), ""):
58 | yield chunk
59 |
60 | 如果你使用的是 Python 3.8
61 | +,还有一种更直观、易于理解的写法,既不用使用偏函数,也不用掌握 iter
62 | 这种另类的用法。而只要用利用 海象运算符就可以,具体代码如下
63 |
64 | .. code:: python
65 |
66 | def read_from_file(filename, block_size = 1024 * 8):
67 | with open(filename, "r") as fp:
68 | while chunk := fp.read(block_size):
69 | yield chunk
70 |
--------------------------------------------------------------------------------
/source/c05/c05_07.md:
--------------------------------------------------------------------------------
1 | # 5.7 实现类似 defer 的延迟调用
2 | 
3 |
4 | 在 Golang 中有一种延迟调用的机制,关键字是 defer,例如下面的示例
5 |
6 | ```go
7 | import "fmt"
8 |
9 | func myfunc() {
10 | fmt.Println("B")
11 | }
12 |
13 | func main() {
14 | defer myfunc()
15 | fmt.Println("A")
16 | }
17 | ```
18 |
19 | 输出如下,myfunc 的调用会在函数返回前一步完成,即使你将 myfunc 的调用写在函数的第一行,这就是延迟调用。
20 |
21 | ```
22 | A
23 | B
24 | ```
25 |
26 | 那么在 Python 中否有这种机制呢?
27 |
28 | 当然也有,只不过并没有 Golang 这种简便。
29 |
30 | 在 Python 可以使用 **上下文管理器** 达到这种效果
31 |
32 | ```python
33 | import contextlib
34 |
35 | def callback():
36 | print('B')
37 |
38 | with contextlib.ExitStack() as stack:
39 | stack.callback(callback)
40 | print('A')
41 | ```
42 |
43 | 输出如下
44 |
45 | ```
46 | A
47 | B
48 | ```
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/source/c05/c05_07.rst:
--------------------------------------------------------------------------------
1 | 5.7 实现类似 defer 的延迟调用
2 | =============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在 Golang 中有一种延迟调用的机制,关键字是 defer,例如下面的示例
7 |
8 | .. code:: go
9 |
10 | import "fmt"
11 |
12 | func myfunc() {
13 | fmt.Println("B")
14 | }
15 |
16 | func main() {
17 | defer myfunc()
18 | fmt.Println("A")
19 | }
20 |
21 | 输出如下,myfunc 的调用会在函数返回前一步完成,即使你将 myfunc
22 | 的调用写在函数的第一行,这就是延迟调用。
23 |
24 | ::
25 |
26 | A
27 | B
28 |
29 | 那么在 Python 中否有这种机制呢?
30 |
31 | 当然也有,只不过并没有 Golang 这种简便。
32 |
33 | 在 Python 可以使用 **上下文管理器** 达到这种效果
34 |
35 | .. code:: python
36 |
37 | import contextlib
38 |
39 | def callback():
40 | print('B')
41 |
42 | with contextlib.ExitStack() as stack:
43 | stack.callback(callback)
44 | print('A')
45 |
46 | 输出如下
47 |
48 | ::
49 |
50 | A
51 | B
52 |
--------------------------------------------------------------------------------
/source/c05/c05_08.md:
--------------------------------------------------------------------------------
1 | # 5.8 如何快速计算函数运行时间
2 | 
3 |
4 | 计算一个函数的运行时间,你可能会这样子做
5 |
6 | ```python
7 | import time
8 |
9 | start = time.time()
10 |
11 | # run the function
12 |
13 | end = time.time()
14 | print(end-start)
15 | ```
16 |
17 | 你看看你为了计算函数运行时间,写了几行代码了。
18 |
19 | 有没有一种方法可以更方便地计算这个运行时间呢?
20 |
21 | 有。
22 |
23 | 有一个内置模块叫 timeit
24 |
25 | 使用它,只用一行代码即可
26 |
27 | ```python
28 | import time
29 | import timeit
30 |
31 | def run_sleep(second):
32 | print(second)
33 | time.sleep(second)
34 |
35 | # 只用这一行
36 | print(timeit.timeit(lambda :run_sleep(2), number=5))
37 | ```
38 |
39 | 运行结果如下
40 |
41 | ```python
42 | 2
43 | 2
44 | 2
45 | 2
46 | 2
47 | 10.020059824
48 | ```
49 |
50 |
51 |
52 |
53 |
--------------------------------------------------------------------------------
/source/c05/c05_08.rst:
--------------------------------------------------------------------------------
1 | 5.8 如何快速计算函数运行时间
2 | ============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 计算一个函数的运行时间,你可能会这样子做
7 |
8 | .. code:: python
9 |
10 | import time
11 |
12 | start = time.time()
13 |
14 | # run the function
15 |
16 | end = time.time()
17 | print(end-start)
18 |
19 | 你看看你为了计算函数运行时间,写了几行代码了。
20 | 有没有一种方法可以更方便地计算这个运行时间呢? 有。 有一个内置模块叫
21 | timeit 使用它,只用一行代码即可
22 |
23 | .. code:: python
24 |
25 | import time
26 | import timeit
27 |
28 | def run_sleep(second):
29 | print(second)
30 | time.sleep(second)
31 |
32 | # 只用这一行
33 | print(timeit.timeit(lambda :run_sleep(2), number=5))
34 |
35 | 运行结果如下
36 |
37 | .. code:: python
38 |
39 | 2
40 | 2
41 | 2
42 | 2
43 | 2
44 | 10.020059824
45 |
--------------------------------------------------------------------------------
/source/c05/c05_09.md:
--------------------------------------------------------------------------------
1 | # 5.9 重定向标准输出到日志
2 | 
3 |
4 | 假设你有一个脚本,会执行一些任务,比如说集群健康情况的检查。
5 |
6 | 检查完成后,会把各服务的的健康状况以 JSON 字符串的形式打印到标准输出。
7 |
8 | 如果代码有问题,导致异常处理不足,最终检查失败,是很有可能将一些错误异常栈输出到标准错误或标准输出上。
9 |
10 | 由于最初约定的脚本返回方式是以 JSON 的格式输出,此时你的脚本却输出各种错误异常,异常调用方也无法解析。
11 |
12 | 如何避免这种情况的发生呢?
13 |
14 | 我们可以这样做,把你的标准错误输出到日志文件中。
15 |
16 | ```python
17 | import contextlib
18 |
19 | log_file="/var/log/you.log"
20 |
21 | def you_task():
22 | pass
23 |
24 | @contextlib.contextmanager
25 | def close_stdout():
26 | raw_stdout = sys.stdout
27 | file = open(log_file, 'a+')
28 | sys.stdout = file
29 |
30 | yield
31 |
32 | sys.stdout = raw_stdout
33 | file.close()
34 |
35 | with close_stdout():
36 | you_task()
37 | ```
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/source/c05/c05_09.rst:
--------------------------------------------------------------------------------
1 | 5.9 重定向标准输出到日志
2 | ========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 假设你有一个脚本,会执行一些任务,比如说集群健康情况的检查。
7 |
8 | 检查完成后,会把各服务的的健康状况以 JSON 字符串的形式打印到标准输出。
9 |
10 | 如果代码有问题,导致异常处理不足,最终检查失败,是很有可能将一些错误异常栈输出到标准错误或标准输出上。
11 |
12 | 由于最初约定的脚本返回方式是以 JSON
13 | 的格式输出,此时你的脚本却输出各种错误异常,异常调用方也无法解析。
14 |
15 | 如何避免这种情况的发生呢?
16 |
17 | 我们可以这样做,把你的标准错误输出到日志文件中。
18 |
19 | .. code:: python
20 |
21 | import contextlib
22 |
23 | log_file="/var/log/you.log"
24 |
25 | def you_task():
26 | pass
27 |
28 | @contextlib.contextmanager
29 | def close_stdout():
30 | raw_stdout = sys.stdout
31 | file = open(log_file, 'a+')
32 | sys.stdout = file
33 |
34 | yield
35 |
36 | sys.stdout = raw_stdout
37 | file.close()
38 |
39 | with close_stdout():
40 | you_task()
41 |
--------------------------------------------------------------------------------
/source/c05/c05_10.md:
--------------------------------------------------------------------------------
1 | # 5.10 快速定位错误进入调试模式
2 | 
3 |
4 | 当你在写一个程序时,最初的程序一定遇到不少零零散散的错误,这时候就免不了调试一波。
5 |
6 | 如果你和我一样,习惯使用 pdb 进行调试的话,一定有所体会,通常我们都要先把 `pdb.set_trace()` 去掉,让程序畅通无阻,直到它把异常抛出来。
7 |
8 | 出现异常后,再使用 vim 跳转到抛出异常的位置,敲入 `import pdb;pdb.set_trace()` ,然后再到运行,进入调试模式,找到问题并修改代码后再去掉我们加上的那行 pdb 的代码。
9 |
10 | 如此反复这样一个过程,直到最后程序没有异常。
11 |
12 | 你应该能够感受到这个过程有多繁锁,令人崩溃。
13 |
14 | 接下来介绍一种,可以让你不需要修改源代码,就可以在异常抛出时,快速切换到调试模式,进入 『案发现场』排查问题。
15 |
16 | 方法很简单,只需要你在执行脚本时,加入 `-i` 参考
17 |
18 | 
19 |
20 | 如果你的程序没有任何问题,加上 `-i` 后又会有什么不一样呢?
21 |
22 | 从下图可以看出,程序执行完成后会自动进入 console 交互模式。
23 |
24 | 
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/source/c05/c05_10.rst:
--------------------------------------------------------------------------------
1 | 5.10 快速定位错误进入调试模式
2 | =============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当你在写一个程序时,最初的程序一定遇到不少零零散散的错误,这时候就免不了调试一波。
7 |
8 | 如果你和我一样,习惯使用 pdb
9 | 进行调试的话,一定有所体会,通常我们都要先把 ``pdb.set_trace()``
10 | 去掉,让程序畅通无阻,直到它把异常抛出来。
11 |
12 | 出现异常后,再使用 vim 跳转到抛出异常的位置,敲入
13 | ``import pdb;pdb.set_trace()``
14 | ,然后再到运行,进入调试模式,找到问题并修改代码后再去掉我们加上的那行
15 | pdb 的代码。
16 |
17 | 如此反复这样一个过程,直到最后程序没有异常。
18 |
19 | 你应该能够感受到这个过程有多繁锁,令人崩溃。
20 |
21 | 接下来介绍一种,可以让你不需要修改源代码,就可以在异常抛出时,快速切换到调试模式,进入
22 | 『案发现场』排查问题。
23 |
24 | 方法很简单,只需要你在执行脚本时,加入 ``-i`` 参考
25 |
26 | .. image:: http://image.iswbm.com/20200615235900.png
27 |
28 | 如果你的程序没有任何问题,加上 ``-i`` 后又会有什么不一样呢?
29 |
30 | 从下图可以看出,程序执行完成后会自动进入 console 交互模式。
31 |
32 | .. image:: http://image.iswbm.com/image-20200616000039009.png
33 |
--------------------------------------------------------------------------------
/source/c05/c05_11.md:
--------------------------------------------------------------------------------
1 | # 5.11 在程序退出前执行代码的技巧
2 | 
3 |
4 | 使用 atexit 这个内置模块,可以很方便地注册退出函数。
5 |
6 | 不管你在哪个地方导致程序崩溃,都会执行那些你注册过的函数。
7 |
8 | 示例如下
9 |
10 | 
11 |
12 | 如果`clean()`函数有参数,那么你可以不用装饰器,而是直接调用`atexit.register(clean_1, 参数1, 参数2, 参数3='xxx')`。
13 |
14 | 可能你有其他方法可以处理这种需求,但肯定比不上使用 atexit 来得优雅,来得方便,并且它很容易扩展。
15 |
16 | 但是使用 atexit 仍然有一些局限性,比如:
17 |
18 | - 如果程序是被你没有处理过的系统信号杀死的,那么注册的函数无法正常执行。
19 | - 如果发生了严重的 Python 内部错误,你注册的函数无法正常执行。
20 | - 如果你手动调用了`os._exit()`,你注册的函数无法正常执行。
21 |
22 |
23 |
--------------------------------------------------------------------------------
/source/c05/c05_11.rst:
--------------------------------------------------------------------------------
1 | 5.11 在程序退出前执行代码的技巧
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 使用 atexit 这个内置模块,可以很方便地注册退出函数。
7 |
8 | 不管你在哪个地方导致程序崩溃,都会执行那些你注册过的函数。
9 |
10 | 示例如下
11 |
12 | .. image:: http://image.iswbm.com/20200510112133.png
13 |
14 | 如果\ ``clean()``\ 函数有参数,那么你可以不用装饰器,而是直接调用\ ``atexit.register(clean_1, 参数1, 参数2, 参数3='xxx')``\ 。
15 |
16 | 可能你有其他方法可以处理这种需求,但肯定比不上使用 atexit
17 | 来得优雅,来得方便,并且它很容易扩展。
18 |
19 | 但是使用 atexit 仍然有一些局限性,比如:
20 |
21 | - 如果程序是被你没有处理过的系统信号杀死的,那么注册的函数无法正常执行。
22 | - 如果发生了严重的 Python 内部错误,你注册的函数无法正常执行。
23 | - 如果你手动调用了\ ``os._exit()``\ ,你注册的函数无法正常执行。
24 |
--------------------------------------------------------------------------------
/source/c05/c05_12.md:
--------------------------------------------------------------------------------
1 | # 5.12 逗号也有它的独特用法
2 | 
3 |
4 | 逗号,虽然是个很不起眼的符号,但在 Python 中也有他的用武之地。
5 |
6 | **第一个用法**
7 |
8 | 元组的转化
9 |
10 | ```shell
11 | [root@localhost ~]# cat demo.py
12 | def func():
13 | return "ok",
14 |
15 | print(func())
16 | [root@localhost ~]# python3 demo.py
17 | ('ok',)
18 | ```
19 |
20 | **第二个用法**
21 |
22 | print 的取消换行
23 |
24 | ```shell
25 | [root@localhost ~]# cat demo.py
26 | for i in range(3):
27 | print i
28 | [root@localhost ~]#
29 | [root@localhost ~]# python demo.py
30 | 0
31 | 1
32 | 2
33 | [root@localhost ~]#
34 | [root@localhost ~]# vim demo.py
35 | [root@localhost ~]#
36 | [root@localhost ~]# cat demo.py
37 | for i in range(3):
38 | print i,
39 | [root@localhost ~]#
40 | [root@localhost ~]# python demo.py
41 | 0 1 2
42 | [root@localhost ~]#
43 | ```
44 |
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/source/c05/c05_12.rst:
--------------------------------------------------------------------------------
1 | 5.12 逗号也有它的独特用法
2 | =========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 逗号,虽然是个很不起眼的符号,但在 Python 中也有他的用武之地。
7 |
8 | **第一个用法**
9 |
10 | 元组的转化
11 |
12 | .. code:: shell
13 |
14 | [root@localhost ~]# cat demo.py
15 | def func():
16 | return "ok",
17 |
18 | print(func())
19 | [root@localhost ~]# python3 demo.py
20 | ('ok',)
21 |
22 | **第二个用法**
23 |
24 | print 的取消换行
25 |
26 | .. code:: shell
27 |
28 | [root@localhost ~]# cat demo.py
29 | for i in range(3):
30 | print i
31 | [root@localhost ~]#
32 | [root@localhost ~]# python demo.py
33 | 0
34 | 1
35 | 2
36 | [root@localhost ~]#
37 | [root@localhost ~]# vim demo.py
38 | [root@localhost ~]#
39 | [root@localhost ~]# cat demo.py
40 | for i in range(3):
41 | print i,
42 | [root@localhost ~]#
43 | [root@localhost ~]# python demo.py
44 | 0 1 2
45 | [root@localhost ~]#
46 |
--------------------------------------------------------------------------------
/source/c05/c05_13.md:
--------------------------------------------------------------------------------
1 | # 5.13 如何在运行状态查看源代码?
2 | 
3 |
4 | 查看函数的源代码,我们通常会使用 IDE 来完成。
5 |
6 | 比如在 PyCharm 中,你可以 Ctrl + 鼠标点击 进入函数的源代码。
7 |
8 | 那如果没有 IDE 呢?
9 |
10 | 当我们想使用一个函数时,如何知道这个函数需要接收哪些参数呢?
11 |
12 | 当我们在使用函数时出现问题的时候,如何通过阅读源代码来排查问题所在呢?
13 |
14 |
15 |
16 | 这时候,我们可以使用 inspect 来代替 IDE 帮助你完成这些事
17 |
18 | ```python
19 | # demo.py
20 | import inspect
21 |
22 |
23 | def add(x, y):
24 | return x + y
25 |
26 | print("===================")
27 | print(inspect.getsource(add))
28 | ```
29 |
30 | 运行结果如下
31 |
32 | ```shell
33 | $ python demo.py
34 | ===================
35 | def add(x, y):
36 | return x + y
37 | ```
38 |
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/source/c05/c05_13.rst:
--------------------------------------------------------------------------------
1 | 5.13 如何在运行状态查看源代码?
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 查看函数的源代码,我们通常会使用 IDE 来完成。
7 |
8 | 比如在 PyCharm 中,你可以 Ctrl + 鼠标点击 进入函数的源代码。
9 |
10 | 那如果没有 IDE 呢?
11 |
12 | 当我们想使用一个函数时,如何知道这个函数需要接收哪些参数呢?
13 |
14 | 当我们在使用函数时出现问题的时候,如何通过阅读源代码来排查问题所在呢?
15 |
16 | 这时候,我们可以使用 inspect 来代替 IDE 帮助你完成这些事
17 |
18 | .. code:: python
19 |
20 | # demo.py
21 | import inspect
22 |
23 |
24 | def add(x, y):
25 | return x + y
26 |
27 | print("===================")
28 | print(inspect.getsource(add))
29 |
30 | 运行结果如下
31 |
32 | .. code:: shell
33 |
34 | $ python demo.py
35 | ===================
36 | def add(x, y):
37 | return x + y
38 |
--------------------------------------------------------------------------------
/source/c05/c05_15.md:
--------------------------------------------------------------------------------
1 | # 5.15 让我爱不释手的用户环境
2 | 
3 |
4 | 当你在机器上并没有 root 权限时,如何安装 Python 的第三方包呢?
5 |
6 | 可以使用 `pip install --user pkg` 将你的包安装在你的用户环境中,该用户环境与全局环境并不冲突,并且多用户之间相互隔离,互不影响。
7 |
8 | ```shell
9 | # 在全局环境中未安装 requests
10 | [root@localhost ~]$ pip list | grep requests
11 | [root@localhost ~]$ su - wangbm
12 |
13 | # 由于用户环境继承自全局环境,这里也未安装
14 | [wangbm@localhost ~]$ pip list | grep requests
15 | [wangbm@localhost ~]$ pip install --user requests
16 | [wangbm@localhost ~]$ pip list | grep requests
17 | requests (2.22.0)
18 | [wangbm@localhost ~]$
19 |
20 | # 从 Location 属性可发现 requests 只安装在当前用户环境中
21 | [wangbm@localhost ~]$ pip show requests
22 | ---
23 | Metadata-Version: 2.1
24 | Name: requests
25 | Version: 2.22.0
26 | Summary: Python HTTP for Humans.
27 | Home-page: http://python-requests.org
28 | Author: Kenneth Reitz
29 | Author-email: me@kennethreitz.org
30 | Installer: pip
31 | License: Apache 2.0
32 | Location: /home/wangbm/.local/lib/python2.7/site-packages
33 | [wangbm@localhost ~]$ exit
34 | logout
35 |
36 | # 退出 wangbm 用户,在 root 用户环境中发现 requests 未安装
37 | [root@localhost ~]$ pip list | grep requests
38 | [root@localhost ~]$
39 | ```
40 |
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/source/c05/c05_15.rst:
--------------------------------------------------------------------------------
1 | 5.15 让我爱不释手的用户环境
2 | ===========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当你在机器上并没有 root 权限时,如何安装 Python 的第三方包呢?
7 |
8 | 可以使用 ``pip install --user pkg``
9 | 将你的包安装在你的用户环境中,该用户环境与全局环境并不冲突,并且多用户之间相互隔离,互不影响。
10 |
11 | .. code:: shell
12 |
13 | # 在全局环境中未安装 requests
14 | [root@localhost ~]$ pip list | grep requests
15 | [root@localhost ~]$ su - wangbm
16 |
17 | # 由于用户环境继承自全局环境,这里也未安装
18 | [wangbm@localhost ~]$ pip list | grep requests
19 | [wangbm@localhost ~]$ pip install --user requests
20 | [wangbm@localhost ~]$ pip list | grep requests
21 | requests (2.22.0)
22 | [wangbm@localhost ~]$
23 |
24 | # 从 Location 属性可发现 requests 只安装在当前用户环境中
25 | [wangbm@localhost ~]$ pip show requests
26 | ---
27 | Metadata-Version: 2.1
28 | Name: requests
29 | Version: 2.22.0
30 | Summary: Python HTTP for Humans.
31 | Home-page: http://python-requests.org
32 | Author: Kenneth Reitz
33 | Author-email: me@kennethreitz.org
34 | Installer: pip
35 | License: Apache 2.0
36 | Location: /home/wangbm/.local/lib/python2.7/site-packages
37 | [wangbm@localhost ~]$ exit
38 | logout
39 |
40 | # 退出 wangbm 用户,在 root 用户环境中发现 requests 未安装
41 | [root@localhost ~]$ pip list | grep requests
42 | [root@localhost ~]$
43 |
--------------------------------------------------------------------------------
/source/c05/c05_16.md:
--------------------------------------------------------------------------------
1 | # 5.16 字符串的分割技巧
2 | 
3 |
4 | 当我们对字符串进行分割时,且分割符是 `\n`,有可能会出现这样一个窘境:
5 |
6 | ```python
7 | >>> str = "a\nb\n"
8 | >>> print(str)
9 | a
10 | b
11 |
12 | >>> str.split('\n')
13 | ['a', 'b', '']
14 | >>>
15 | ```
16 |
17 | 会在最后一行多出一个元素,这可就太多余了吧。
18 |
19 | 实际上对于这种情况,你可以直接这样子
20 |
21 | ```python
22 | >>> str = "a\nb\n"
23 | >>>
24 | >>> str.split()
25 | ['a', 'b']
26 | ```
27 |
28 | 即使是多个换行符,也照样适用
29 |
30 | ```python
31 | >>> str = "a\n\nb\n\n"
32 | >>>
33 | >>> str.split()
34 | ['a', 'b']
35 | ```
36 |
37 | 有的人还会建议使用 `splitlines`
38 |
39 | ```python
40 | >>> str = "a\nb\n"
41 | >>>
42 | >>> str.splitlines()
43 | ['a', 'b']
44 | ```
45 |
46 | 但其实,splitlines 方法只有在上面这种仅一个换行符的场景下,才能达到如上预期的。比如下边的案例,就无法适用:
47 |
48 | ```python
49 | >>> str = "a\n\nb\n\n"
50 | >>>
51 | >>> str.splitlines()
52 | ['a', '', 'b', '']
53 | ```
54 |
55 | 在这里有必要补充下,对 splitlines 的原理做一些说明
56 |
57 | 其实 splitlines 函数还有一个 keepends 参数 ,意思是 **是否要保留换行符** ('\r', '\r\n', '\n')
58 |
59 | 默认值为 False,也正是这个原因,上面的例子才有那样的效果 -- **去掉了最后一个元素**
60 |
61 | 试着指定该参数为 True,你就会发现,原来 splitlines 是为换行符为界将字符串分成多个,但并不是直接拿掉换行符。
62 |
63 | ```python
64 | >>> str = "a\nb\n"
65 | >>> str.splitlines(True)
66 | ['a\n', 'b\n']
67 | ```
68 |
69 | 因此在多个换行符的情况下,请务必使用 split 方法。
70 |
71 |
72 |
--------------------------------------------------------------------------------
/source/c05/c05_16.rst:
--------------------------------------------------------------------------------
1 | 5.16 字符串的分割技巧
2 | =====================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当我们对字符串进行分割时,且分割符是
7 | ``\n``\ ,有可能会出现这样一个窘境:
8 |
9 | .. code:: python
10 |
11 | >>> str = "a\nb\n"
12 | >>> print(str)
13 | a
14 | b
15 |
16 | >>> str.split('\n')
17 | ['a', 'b', '']
18 | >>>
19 |
20 | 会在最后一行多出一个元素,这可就太多余了吧。
21 |
22 | 实际上对于这种情况,你可以直接这样子
23 |
24 | .. code:: python
25 |
26 | >>> str = "a\nb\n"
27 | >>>
28 | >>> str.split()
29 | ['a', 'b']
30 |
31 | 即使是多个换行符,也照样适用
32 |
33 | .. code:: python
34 |
35 | >>> str = "a\n\nb\n\n"
36 | >>>
37 | >>> str.split()
38 | ['a', 'b']
39 |
40 | 有的人还会建议使用 ``splitlines``
41 |
42 | .. code:: python
43 |
44 | >>> str = "a\nb\n"
45 | >>>
46 | >>> str.splitlines()
47 | ['a', 'b']
48 |
49 | 但其实,splitlines
50 | 方法只有在上面这种仅一个换行符的场景下,才能达到如上预期的。比如下边的案例,就无法适用:
51 |
52 | .. code:: python
53 |
54 | >>> str = "a\n\nb\n\n"
55 | >>>
56 | >>> str.splitlines()
57 | ['a', '', 'b', '']
58 |
59 | 在这里有必要补充下,对 splitlines 的原理做一些说明
60 |
61 | 其实 splitlines 函数还有一个 keepends 参数 ,意思是 **是否要保留换行符**
62 | (‘:raw-latex:`\r'`,’:raw-latex:`\r\n`‘,’:raw-latex:`\n`’)
63 |
64 | 默认值为 False,也正是这个原因,上面的例子才有那样的效果 –
65 | **去掉了最后一个元素**
66 |
67 | 试着指定该参数为 True,你就会发现,原来 splitlines
68 | 是为换行符为界将字符串分成多个,但并不是直接拿掉换行符。
69 |
70 | .. code:: python
71 |
72 | >>> str = "a\nb\n"
73 | >>> str.splitlines(True)
74 | ['a\n', 'b\n']
75 |
76 | 因此在多个换行符的情况下,请务必使用 split 方法。
77 |
--------------------------------------------------------------------------------
/source/c05/c05_17.md:
--------------------------------------------------------------------------------
1 | # 5.17 反转字符串/列表最优雅的方式
2 | 
3 |
4 | 反转序列并不难,但是如何做到最优雅呢?
5 |
6 | 先来看看,正常是如何反转的。
7 |
8 | 最简单的方法是使用列表自带的reverse()方法。
9 |
10 | ```python
11 | >>> ml = [1,2,3,4,5]
12 | >>> ml.reverse()
13 | >>> ml
14 | [5, 4, 3, 2, 1]
15 | ```
16 |
17 | 但如果你要处理的是字符串,reverse就无能为力了。你可以尝试将其转化成list,再reverse,然后再转化成str。转来转去,也太麻烦了吧?需要这么多行代码(后面三行是不能合并成一行的),一点都不Pythonic。
18 |
19 | ```python
20 | mstr1 = 'abc'
21 | ml1 = list(mstr1)
22 | ml1.reverse()
23 | mstr2 = str(ml1)
24 | ```
25 |
26 | 对于字符串还有一种稍微复杂一点的,是自定义递归函数来实现。
27 |
28 | ```python
29 | def my_reverse(str):
30 | if str == "":
31 | return str
32 | else:
33 | return my_reverse(str[1:]) + str[0]
34 | ```
35 |
36 | 在这里,介绍一种最优雅的反转方式,使用切片,不管你是字符串,还是列表,简直通杀。
37 |
38 | ```python
39 | >>> mstr = 'abc'
40 | >>> ml = [1,2,3]
41 | >>> mstr[::-1]
42 | 'cba'
43 | >>> ml[::-1]
44 | [3, 2, 1]
45 | ```
46 |
47 |
48 |
--------------------------------------------------------------------------------
/source/c05/c05_17.rst:
--------------------------------------------------------------------------------
1 | 5.17 反转字符串/列表最优雅的方式
2 | ================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 反转序列并不难,但是如何做到最优雅呢?
7 |
8 | 先来看看,正常是如何反转的。
9 |
10 | 最简单的方法是使用列表自带的reverse()方法。
11 |
12 | .. code:: python
13 |
14 | >>> ml = [1,2,3,4,5]
15 | >>> ml.reverse()
16 | >>> ml
17 | [5, 4, 3, 2, 1]
18 |
19 | 但如果你要处理的是字符串,reverse就无能为力了。你可以尝试将其转化成list,再reverse,然后再转化成str。转来转去,也太麻烦了吧?需要这么多行代码(后面三行是不能合并成一行的),一点都不Pythonic。
20 |
21 | .. code:: python
22 |
23 | mstr1 = 'abc'
24 | ml1 = list(mstr1)
25 | ml1.reverse()
26 | mstr2 = str(ml1)
27 |
28 | 对于字符串还有一种稍微复杂一点的,是自定义递归函数来实现。
29 |
30 | .. code:: python
31 |
32 | def my_reverse(str):
33 | if str == "":
34 | return str
35 | else:
36 | return my_reverse(str[1:]) + str[0]
37 |
38 | 在这里,介绍一种最优雅的反转方式,使用切片,不管你是字符串,还是列表,简直通杀。
39 |
40 | .. code:: python
41 |
42 | >>> mstr = 'abc'
43 | >>> ml = [1,2,3]
44 | >>> mstr[::-1]
45 | 'cba'
46 | >>> ml[::-1]
47 | [3, 2, 1]
48 |
--------------------------------------------------------------------------------
/source/c05/c05_18.md:
--------------------------------------------------------------------------------
1 | # 5.18 如何将 print 内容输出到文件
2 | 
3 |
4 | Python 3 中的 print 作为一个函数,由于可以接收更多的参数,所以功能变为更加强大。
5 |
6 | 比如今天要说的使用 print 将你要打印的内容,输出到日志文件中(但是我并不推荐使用它)。
7 |
8 | ```python
9 | >>> with open('test.log', mode='w') as f:
10 | ... print('hello, python', file=f, flush=True)
11 | >>> exit()
12 |
13 | $ cat test.log
14 | hello, python
15 | ```
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/source/c05/c05_18.rst:
--------------------------------------------------------------------------------
1 | 5.18 如何将 print 内容输出到文件
2 | ================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | Python 3 中的 print
7 | 作为一个函数,由于可以接收更多的参数,所以功能变为更加强大。
8 |
9 | 比如今天要说的使用 print
10 | 将你要打印的内容,输出到日志文件中(但是我并不推荐使用它)。
11 |
12 | .. code:: python
13 |
14 | >>> with open('test.log', mode='w') as f:
15 | ... print('hello, python', file=f, flush=True)
16 | >>> exit()
17 |
18 | $ cat test.log
19 | hello, python
20 |
--------------------------------------------------------------------------------
/source/c05/c05_19.md:
--------------------------------------------------------------------------------
1 | # 5.19 改变默认递归次数限制
2 | 
3 |
4 | 上面才提到递归,大家都知道使用递归是有风险的,递归深度过深容易导致堆栈的溢出。如果你这字符串太长啦,使用递归方式反转,就会出现问题。
5 |
6 | 那到底,默认递归次数限制是多少呢?
7 |
8 | ```python
9 | >>> import sys
10 | >>> sys.getrecursionlimit()
11 | 1000
12 | ```
13 |
14 | 可以查,当然也可以自定义修改次数,退出即失效。
15 |
16 | ```python
17 | >>> sys.setrecursionlimit(2000)
18 | >>> sys.getrecursionlimit()
19 | 2000
20 | ```
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/source/c05/c05_19.rst:
--------------------------------------------------------------------------------
1 | 5.19 改变默认递归次数限制
2 | =========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 上面才提到递归,大家都知道使用递归是有风险的,递归深度过深容易导致堆栈的溢出。如果你这字符串太长啦,使用递归方式反转,就会出现问题。
7 |
8 | 那到底,默认递归次数限制是多少呢?
9 |
10 | .. code:: python
11 |
12 | >>> import sys
13 | >>> sys.getrecursionlimit()
14 | 1000
15 |
16 | 可以查,当然也可以自定义修改次数,退出即失效。
17 |
18 | .. code:: python
19 |
20 | >>> sys.setrecursionlimit(2000)
21 | >>> sys.getrecursionlimit()
22 | 2000
23 |
--------------------------------------------------------------------------------
/source/c05/c05_20.md:
--------------------------------------------------------------------------------
1 | # 5.20 让你晕头转向的 else 用法
2 | 
3 |
4 | if else 用法可以说是最基础的语法表达式之一,但是今天不是讲这个的。
5 |
6 | if else 早已烂大街,但我相信仍然有很多人都不曾见过 for else 和 try else 的用法。为什么说它曾让我晕头转向,因为它不像 if else 那么直白,非黑即白,脑子经常要想一下才能才反应过来代码怎么走。
7 |
8 | 先来说说,for ... else ...
9 |
10 | ```python
11 | def check_item(source_list, target):
12 | for item in source_list:
13 | if item == target:
14 | print("Exists!")
15 | break
16 |
17 | else:
18 | print("Does not exist")
19 |
20 | ```
21 |
22 | 在往下看之前,你可以思考一下,什么情况下才会走 else。是循环被 break,还是没有break?
23 |
24 | 给几个例子,你体会一下。
25 |
26 | ```python
27 | check_item(["apple", "huawei", "oppo"], "oppo")
28 | # Exists!
29 |
30 | check_item(["apple", "huawei", "oppo"], "vivo")
31 | # Does not exist
32 | ```
33 |
34 | 可以看出,没有被 break 的程序才会正常走else流程。
35 |
36 | 再来看看,try else 用法。
37 |
38 | ```python
39 | def test_try_else(attr1 = None):
40 | try:
41 | if attr1:
42 | pass
43 | else:
44 | raise
45 | except:
46 | print("Exception occurred...")
47 | else:
48 | print("No Exception occurred...")
49 | ```
50 |
51 | 同样来几个例子。当不传参数时,就抛出异常。
52 |
53 | ```python
54 | test_try_else()
55 | # Exception occurred...
56 |
57 | test_try_else("ming")
58 | # No Exception occurred...
59 | ```
60 |
61 | 可以看出, try 里面的代码块没有抛出异常的,会正常走else。
62 |
63 | 总结一下,for else 和 try else 相同,只要代码正常走下去不被 break,不抛出异常,就可以走else。
64 |
65 |
--------------------------------------------------------------------------------
/source/c05/c05_20.rst:
--------------------------------------------------------------------------------
1 | 5.20 让你晕头转向的 else 用法
2 | =============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | if else 用法可以说是最基础的语法表达式之一,但是今天不是讲这个的。
7 |
8 | if else 早已烂大街,但我相信仍然有很多人都不曾见过 for else 和 try else
9 | 的用法。为什么说它曾让我晕头转向,因为它不像 if else
10 | 那么直白,非黑即白,脑子经常要想一下才能才反应过来代码怎么走。
11 |
12 | 先来说说,for … else …
13 |
14 | .. code:: python
15 |
16 | def check_item(source_list, target):
17 | for item in source_list:
18 | if item == target:
19 | print("Exists!")
20 | break
21 |
22 | else:
23 | print("Does not exist")
24 |
25 | 在往下看之前,你可以思考一下,什么情况下才会走 else。是循环被
26 | break,还是没有break?
27 |
28 | 给几个例子,你体会一下。
29 |
30 | .. code:: python
31 |
32 | check_item(["apple", "huawei", "oppo"], "oppo")
33 | # Exists!
34 |
35 | check_item(["apple", "huawei", "oppo"], "vivo")
36 | # Does not exist
37 |
38 | 可以看出,没有被 break 的程序才会正常走else流程。
39 |
40 | 再来看看,try else 用法。
41 |
42 | .. code:: python
43 |
44 | def test_try_else(attr1 = None):
45 | try:
46 | if attr1:
47 | pass
48 | else:
49 | raise
50 | except:
51 | print("Exception occurred...")
52 | else:
53 | print("No Exception occurred...")
54 |
55 | 同样来几个例子。当不传参数时,就抛出异常。
56 |
57 | .. code:: python
58 |
59 | test_try_else()
60 | # Exception occurred...
61 |
62 | test_try_else("ming")
63 | # No Exception occurred...
64 |
65 | 可以看出, try 里面的代码块没有抛出异常的,会正常走else。
66 |
67 | 总结一下,for else 和 try else 相同,只要代码正常走下去不被
68 | break,不抛出异常,就可以走else。
69 |
--------------------------------------------------------------------------------
/source/c05/c05_21.md:
--------------------------------------------------------------------------------
1 | # 5.21 字典访问不存在的key时不再报错
2 |
3 | 
4 |
5 | 当一个字典里没有某个 key 时,此时你访问他是会报 KeyError 的。
6 |
7 | ```python
8 | >>> profile={}
9 | >>> profile["age"]
10 | Traceback (most recent call last):
11 | File "", line 1, in
12 | KeyError: 'age'
13 | ```
14 |
15 | 这里有一个小技巧,使用 collections 的 defaultdict 方法,可以帮你处理这个小问题,当你访问一个不存在的 key 时,会返回默认值。
16 |
17 | defaultdict 接收一个工厂方法,工厂方法返回的对象就是字典的默认值。
18 |
19 | 常用的工厂方法有,我们常见的 int,str,bool 等
20 |
21 | ```python
22 | >>> a=int()
23 | >>> a
24 | 0
25 | >>>
26 | >>> b=str()
27 | >>> b
28 | ''
29 | >>>
30 | >>> c=bool()
31 | >>> c
32 | False
33 | ```
34 |
35 | 因为 defaultdict 可以这样子用。
36 |
37 | ```python
38 | >>> import collections
39 | >>> profile=collections.defaultdict(int)
40 | >>> profile
41 | defaultdict(, {})
42 | >>> profile["age"]
43 | 0
44 | >>> profile=collections.defaultdict(str)
45 | >>> profile
46 | defaultdict(, {})
47 | >>> profile["name"]
48 | ''
49 | ```
50 |
51 | 当然既然是工厂方法,你也可以使用 lambda 匿名函数来实现自定义的效果,比如我们使用 str 就会设置一个空字符串,但这并不是我想要的,我想要的是设置一个其他字符串,你就可以像下面这样子。
52 |
53 | ```python
54 | >>> info=collections.defaultdict(lambda: "default value")
55 | >>> info
56 | defaultdict( at 0x10ff10488>, {})
57 | >>>
58 | >>> info["msg"]
59 | 'default value'
60 | ```
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/source/c05/c05_21.rst:
--------------------------------------------------------------------------------
1 | 5.21 字典访问不存在的key时不再报错
2 | ==================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当一个字典里没有某个 key 时,此时你访问他是会报 KeyError 的。
7 |
8 | .. code:: python
9 |
10 | >>> profile={}
11 | >>> profile["age"]
12 | Traceback (most recent call last):
13 | File "", line 1, in
14 | KeyError: 'age'
15 |
16 | 这里有一个小技巧,使用 collections 的 defaultdict
17 | 方法,可以帮你处理这个小问题,当你访问一个不存在的 key
18 | 时,会返回默认值。
19 |
20 | defaultdict 接收一个工厂方法,工厂方法返回的对象就是字典的默认值。
21 |
22 | 常用的工厂方法有,我们常见的 int,str,bool 等
23 |
24 | .. code:: python
25 |
26 | >>> a=int()
27 | >>> a
28 | 0
29 | >>>
30 | >>> b=str()
31 | >>> b
32 | ''
33 | >>>
34 | >>> c=bool()
35 | >>> c
36 | False
37 |
38 | 因为 defaultdict 可以这样子用。
39 |
40 | .. code:: python
41 |
42 | >>> import collections
43 | >>> profile=collections.defaultdict(int)
44 | >>> profile
45 | defaultdict(, {})
46 | >>> profile["age"]
47 | 0
48 | >>> profile=collections.defaultdict(str)
49 | >>> profile
50 | defaultdict(, {})
51 | >>> profile["name"]
52 | ''
53 |
54 | 当然既然是工厂方法,你也可以使用 lambda
55 | 匿名函数来实现自定义的效果,比如我们使用 str
56 | 就会设置一个空字符串,但这并不是我想要的,我想要的是设置一个其他字符串,你就可以像下面这样子。
57 |
58 | .. code:: python
59 |
60 | >>> info=collections.defaultdict(lambda: "default value")
61 | >>> info
62 | defaultdict( at 0x10ff10488>, {})
63 | >>>
64 | >>> info["msg"]
65 | 'default value'
66 |
--------------------------------------------------------------------------------
/source/c05/c05_22.md:
--------------------------------------------------------------------------------
1 | # 5.22 如何实现函数的连续调用?
2 |
3 | 
4 |
5 | 现在我想写一个函数可以实现把所有的数进行求和,并且可以达到反复调用的目的。
6 |
7 | 比如这样子。
8 |
9 | ```python
10 | >>> add(2)(3)(4)(5)(6)(7)
11 | 27
12 | ```
13 |
14 | 当只调用一次时,也必须适用。
15 |
16 | ```python
17 | >>> add(2)
18 | 2
19 | ```
20 |
21 | 每次调用的返回结果都是一个 int 类型的实例,要实现将一个实例看做一个函数一样调用,那就不得不使用到 `__call__` 这个魔法方法。
22 |
23 | ```python
24 | >>> class AddInt(int):
25 | ... def __call__(self, x):
26 | ... print("calling __call__ function")
27 | ... return AddInt(self.numerator + x)
28 | ...
29 | >>>
30 | >>> age = AddInt(18)
31 | >>> age
32 | 18
33 | >>> age(1)
34 | calling __call__ function
35 | 19
36 | ```
37 |
38 | 有了上面的铺垫,可以在 AddInt 外层再加一层封装即可。
39 |
40 | ```python
41 | >>> def add(x):
42 | ... class AddInt(int):
43 | ... def __call__(self, x):
44 | ... return AddInt(self.numerator + x)
45 | ... return AddInt(x)
46 | ...
47 | >>> add(2)
48 | 2
49 | >>> add(2)(3)(4)(5)(6)(7)
50 | 27
51 | >>>
52 | ```
53 |
54 |
--------------------------------------------------------------------------------
/source/c05/c05_22.rst:
--------------------------------------------------------------------------------
1 | 5.22 如何实现函数的连续调用?
2 | =============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 现在我想写一个函数可以实现把所有的数进行求和,并且可以达到反复调用的目的。
7 |
8 | 比如这样子。
9 |
10 | .. code:: python
11 |
12 | >>> add(2)(3)(4)(5)(6)(7)
13 | 27
14 |
15 | 当只调用一次时,也必须适用。
16 |
17 | .. code:: python
18 |
19 | >>> add(2)
20 | 2
21 |
22 | 每次调用的返回结果都是一个 int
23 | 类型的实例,要实现将一个实例看做一个函数一样调用,那就不得不使用到
24 | ``__call__`` 这个魔法方法。
25 |
26 | .. code:: python
27 |
28 | >>> class AddInt(int):
29 | ... def __call__(self, x):
30 | ... print("calling __call__ function")
31 | ... return AddInt(self.numerator + x)
32 | ...
33 | >>>
34 | >>> age = AddInt(18)
35 | >>> age
36 | 18
37 | >>> age(1)
38 | calling __call__ function
39 | 19
40 |
41 | 有了上面的铺垫,可以在 AddInt 外层再加一层封装即可。
42 |
43 | .. code:: python
44 |
45 | >>> def add(x):
46 | ... class AddInt(int):
47 | ... def __call__(self, x):
48 | ... return AddInt(self.numerator + x)
49 | ... return AddInt(x)
50 | ...
51 | >>> add(2)
52 | 2
53 | >>> add(2)(3)(4)(5)(6)(7)
54 | 27
55 | >>>
56 |
--------------------------------------------------------------------------------
/source/c05/c05_23.md:
--------------------------------------------------------------------------------
1 | # 5.23 如何实现字典的多级排序
2 |
3 | 
4 |
5 | 在一个列表中,每个元素都是一个字典,里面的每个字典结构都是一样的。
6 |
7 | 里面的每个字典会有多个键值对,根据某个 key 或 value 的值大小,对该列表进行排序,使用 sort 函数就可以轻松实现。
8 |
9 | ```python
10 | >>> students = [{'name': 'Jack', 'age': 17, 'score': 89}, {'name': 'Julia', 'age': 17, 'score': 80}, {'name': 'Tom', 'age': 16, 'score': 80}]
11 | >>> students.sort(key=lambda student: student['score'])
12 | >>> students
13 | [{'age': 17, 'score': 80, 'name': 'Julia'}, {'age': 16, 'score': 80, 'name': 'Tom'}, {'age': 17, 'score': 89, 'name': 'Jack'}]
14 | ```
15 |
16 | 如果两名同学的成绩一样,那谁排在前面呢?
17 |
18 | 那就再额外定个第二指标呗,成绩一样,就再看年龄,年龄小的,成绩还能一样,那不是更历害嘛 。
19 |
20 | 规则定下了:先按成绩升序,如果成绩一致,再按年龄升序。
21 |
22 | 问题来了,这样的规则,代码该如何实现呢?
23 |
24 | 用字典本身的 sort 函数也能实现,方法如下:
25 |
26 | ```python
27 | >>> students = [{'name': 'Jack', 'age': 17, 'score': 89}, {'name': 'Julia', 'age': 17, 'score': 80}, {'name': 'Tom', 'age': 16, 'score': 80}]
28 | >>> students.sort(key=lambda student: (student['score'], student['age']))
29 | >>> students
30 | [{'age': 16, 'score': 80, 'name': 'Tom'}, {'age': 17, 'score': 80, 'name': 'Julia'}, {'age': 17, 'score': 89, 'name': 'Jack'}]
31 | ```
32 |
33 | 那如果一个降序,而另一个是升序,那又该怎么写呢?
34 |
35 | 很简单,只要在对应的 key 上,前面加一个负号,就会把顺序给颠倒过来。
36 |
37 | 还是以上面为例,我现在要实现先按成绩降序,如果成绩一致,再按年龄升序。可以这样写
38 |
39 | ```python
40 | >>> students = [{'name': 'Jack', 'age': 17, 'score': 89}, {'name': 'Julia', 'age': 17, 'score': 80}, {'name': 'Tom', 'age': 16, 'score': 80}]
41 | >>> students.sort(key=lambda student: (-student['score'], student['age']))
42 | >>> students
43 | [{'age': 17, 'score': 80, 'name': 'Julia'}, {'age': 16, 'score': 80, 'name': 'Tom'}, {'age': 17, 'score': 89, 'name': 'Jack'}]
44 | ```
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/source/c05/c05_23.rst:
--------------------------------------------------------------------------------
1 | 5.23 如何实现字典的多级排序
2 | ===========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在一个列表中,每个元素都是一个字典,里面的每个字典结构都是一样的。
7 |
8 | 里面的每个字典会有多个键值对,根据某个 key 或 value
9 | 的值大小,对该列表进行排序,使用 sort 函数就可以轻松实现。
10 |
11 | .. code:: python
12 |
13 | >>> students = [{'name': 'Jack', 'age': 17, 'score': 89}, {'name': 'Julia', 'age': 17, 'score': 80}, {'name': 'Tom', 'age': 16, 'score': 80}]
14 | >>> students.sort(key=lambda student: student['score'])
15 | >>> students
16 | [{'age': 17, 'score': 80, 'name': 'Julia'}, {'age': 16, 'score': 80, 'name': 'Tom'}, {'age': 17, 'score': 89, 'name': 'Jack'}]
17 |
18 | 如果两名同学的成绩一样,那谁排在前面呢?
19 |
20 | 那就再额外定个第二指标呗,成绩一样,就再看年龄,年龄小的,成绩还能一样,那不是更历害嘛
21 | 。
22 |
23 | 规则定下了:先按成绩升序,如果成绩一致,再按年龄升序。
24 |
25 | 问题来了,这样的规则,代码该如何实现呢?
26 |
27 | 用字典本身的 sort 函数也能实现,方法如下:
28 |
29 | .. code:: python
30 |
31 | >>> students = [{'name': 'Jack', 'age': 17, 'score': 89}, {'name': 'Julia', 'age': 17, 'score': 80}, {'name': 'Tom', 'age': 16, 'score': 80}]
32 | >>> students.sort(key=lambda student: (student['score'], student['age']))
33 | >>> students
34 | [{'age': 16, 'score': 80, 'name': 'Tom'}, {'age': 17, 'score': 80, 'name': 'Julia'}, {'age': 17, 'score': 89, 'name': 'Jack'}]
35 |
36 | 那如果一个降序,而另一个是升序,那又该怎么写呢?
37 |
38 | 很简单,只要在对应的 key 上,前面加一个负号,就会把顺序给颠倒过来。
39 |
40 | 还是以上面为例,我现在要实现先按成绩降序,如果成绩一致,再按年龄升序。可以这样写
41 |
42 | .. code:: python
43 |
44 | >>> students = [{'name': 'Jack', 'age': 17, 'score': 89}, {'name': 'Julia', 'age': 17, 'score': 80}, {'name': 'Tom', 'age': 16, 'score': 80}]
45 | >>> students.sort(key=lambda student: (-student['score'], student['age']))
46 | >>> students
47 | [{'age': 17, 'score': 80, 'name': 'Julia'}, {'age': 16, 'score': 80, 'name': 'Tom'}, {'age': 17, 'score': 89, 'name': 'Jack'}]
48 |
--------------------------------------------------------------------------------
/source/c05/c05_25.md:
--------------------------------------------------------------------------------
1 | # 5.25 将位置参数变成关键字参数
2 |
3 | 
4 |
5 | 在 Python 中,参数的种类,大概可以分为四种:
6 |
7 | 1. `必选参数`,也叫`位置参数`,调用函数时一定指定的参数,并且在传参的时候必须按函数定义时的顺序来
8 | 2. `可选参数`,也叫`默认参数`,调用函数时,可以指定也可以不指定,不指定就按默认的参数值来。
9 | 3. `可变参数`,就是参数个数可变,可以是 0 个或者任意个,但是传参时不能指定参数名,通常使用 `*args` 来表示。
10 | 4. `关键字参数`,就是参数个数可变,可以是 0 个或者任意个,但是传参时必须指定参数名,通常使用 `**kw` 来表示
11 |
12 | 使用单独的 `*`,可以将后面的位置参数变成关键字参数,关键字参数在你传参时,必须要写参数名,不然会报错。
13 |
14 | ```python
15 | >>> def demo_func(a, b, *, c):
16 | ... print(a)
17 | ... print(b)
18 | ... print(c)
19 | ...
20 | >>>
21 | >>> demo_func(1, 2, 3)
22 | Traceback (most recent call last):
23 | File "", line 1, in
24 | TypeError: demo_func() takes 2 positional arguments but 3 were given
25 | >>>
26 | >>> demo_func(1, 2, c=3)
27 | 1
28 | 2
29 | 3
30 | ```
31 |
32 |
--------------------------------------------------------------------------------
/source/c05/c05_25.rst:
--------------------------------------------------------------------------------
1 | 5.25 将位置参数变成关键字参数
2 | =============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在 Python 中,参数的种类,大概可以分为四种:
7 |
8 | 1. ``必选参数``\ ,也叫\ ``位置参数``\ ,调用函数时一定指定的参数,并且在传参的时候必须按函数定义时的顺序来
9 | 2. ``可选参数``\ ,也叫\ ``默认参数``\ ,调用函数时,可以指定也可以不指定,不指定就按默认的参数值来。
10 | 3. ``可变参数``\ ,就是参数个数可变,可以是 0
11 | 个或者任意个,但是传参时不能指定参数名,通常使用 ``*args`` 来表示。
12 | 4. ``关键字参数``\ ,就是参数个数可变,可以是 0
13 | 个或者任意个,但是传参时必须指定参数名,通常使用 ``**kw`` 来表示
14 |
15 | 使用单独的
16 | ``*``\ ,可以将后面的位置参数变成关键字参数,关键字参数在你传参时,必须要写参数名,不然会报错。
17 |
18 | .. code:: python
19 |
20 | >>> def demo_func(a, b, *, c):
21 | ... print(a)
22 | ... print(b)
23 | ... print(c)
24 | ...
25 | >>>
26 | >>> demo_func(1, 2, 3)
27 | Traceback (most recent call last):
28 | File "", line 1, in
29 | TypeError: demo_func() takes 2 positional arguments but 3 were given
30 | >>>
31 | >>> demo_func(1, 2, c=3)
32 | 1
33 | 2
34 | 3
35 |
--------------------------------------------------------------------------------
/source/c05/c05_26.md:
--------------------------------------------------------------------------------
1 | # 5.26 如何获取一个函数设定的参数
2 |
3 | 
4 |
5 | 在 Python 中有一个叫 inspect 的库,非常的好用,利用它可以获取一些数据,这在写一些框架时非常有用。
6 |
7 | 比如有下面这样一个函数
8 |
9 | ```python
10 | def demo(name, age, gender="male", *args, **kw):
11 | pass
12 | ```
13 |
14 | 使用 inspect 可以直接获取
15 |
16 | ```python
17 | >>> from inspect import signature
18 | >>>
19 | >>> sig = signature(demo) # # 获取函数签名
20 | >>> sig
21 |
22 | ```
23 |
24 | 利用 inspect 还可以检查传参是否匹配签名
25 |
26 | ```python
27 | >>> sig.bind("王炳明", 27)
28 |
29 | >>>
30 | >>> sig.bind("王炳明")
31 | Traceback (most recent call last):
32 | File "", line 1, in
33 | File "/usr/lib64/python3.6/inspect.py", line 2997, in bind
34 | return args[0]._bind(args[1:], kwargs)
35 | File "/usr/lib64/python3.6/inspect.py", line 2912, in _bind
36 | raise TypeError(msg) from None
37 | TypeError: missing a required argument: 'age'
38 | ```
39 |
40 |
--------------------------------------------------------------------------------
/source/c05/c05_26.rst:
--------------------------------------------------------------------------------
1 | 5.26 如何获取一个函数设定的参数
2 | ===============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在 Python 中有一个叫 inspect
7 | 的库,非常的好用,利用它可以获取一些数据,这在写一些框架时非常有用。
8 |
9 | 比如有下面这样一个函数
10 |
11 | .. code:: python
12 |
13 | def demo(name, age, gender="male", *args, **kw):
14 | pass
15 |
16 | 使用 inspect 可以直接获取
17 |
18 | .. code:: python
19 |
20 | >>> from inspect import signature
21 | >>>
22 | >>> sig = signature(demo) # # 获取函数签名
23 | >>> sig
24 |
25 |
26 | 利用 inspect 还可以检查传参是否匹配签名
27 |
28 | .. code:: python
29 |
30 | >>> sig.bind("王炳明", 27)
31 |
32 | >>>
33 | >>> sig.bind("王炳明")
34 | Traceback (most recent call last):
35 | File "", line 1, in
36 | File "/usr/lib64/python3.6/inspect.py", line 2997, in bind
37 | return args[0]._bind(args[1:], kwargs)
38 | File "/usr/lib64/python3.6/inspect.py", line 2912, in _bind
39 | raise TypeError(msg) from None
40 | TypeError: missing a required argument: 'age'
41 |
--------------------------------------------------------------------------------
/source/c05/c05_27.md:
--------------------------------------------------------------------------------
1 | # 5.27 如何进行版本的比较
2 |
3 | 
4 |
5 | ## 使用 distutils
6 |
7 | `distutils` 是 Python 的内置模块,它做为最古老的 python 分发工具,本身也实现了版本的比较与检查的功能。
8 |
9 | ```python
10 | >>> from distutils.version import LooseVersion, StrictVersion
11 | >>> LooseVersion("2.3.1") < LooseVersion("10.1.2")
12 | True
13 | >>> StrictVersion("2.3.1") < StrictVersion("10.1.2")
14 | True
15 | ```
16 |
17 | ## 使用 packaging
18 |
19 | 如果你的环境中安装过 `setuptools`,那么一定会附带安装了 packaging 这个包,而如果你的环境中并没有 setuptools ,也可以通过 pip 来快速安装
20 |
21 | ```shell
22 | $ python3 -m pip install packaging
23 | ```
24 |
25 | 在 packaging 中有一个 version 模块,专门用来为 setuptools 提供包版本的版本解析。
26 |
27 | ```python
28 | >>> from packaging import version
29 | >>> version.parse("2.3.1") < version.parse("10.1.2")
30 | True
31 | >>> version.parse("1.3.a4") < version.parse("10.1.2")
32 | True
33 | ```
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/source/c05/c05_27.rst:
--------------------------------------------------------------------------------
1 | 5.27 如何进行版本的比较
2 | =======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 使用 distutils
7 | --------------
8 |
9 | ``distutils`` 是 Python 的内置模块,它做为最古老的 python
10 | 分发工具,本身也实现了版本的比较与检查的功能。
11 |
12 | .. code:: python
13 |
14 | >>> from distutils.version import LooseVersion, StrictVersion
15 | >>> LooseVersion("2.3.1") < LooseVersion("10.1.2")
16 | True
17 | >>> StrictVersion("2.3.1") < StrictVersion("10.1.2")
18 | True
19 |
20 | 使用 packaging
21 | --------------
22 |
23 | 如果你的环境中安装过 ``setuptools``\ ,那么一定会附带安装了 packaging
24 | 这个包,而如果你的环境中并没有 setuptools ,也可以通过 pip 来快速安装
25 |
26 | .. code:: shell
27 |
28 | $ python3 -m pip install packaging
29 |
30 | 在 packaging 中有一个 version 模块,专门用来为 setuptools
31 | 提供包版本的版本解析。
32 |
33 | .. code:: python
34 |
35 | >>> from packaging import version
36 | >>> version.parse("2.3.1") < version.parse("10.1.2")
37 | True
38 | >>> version.parse("1.3.a4") < version.parse("10.1.2")
39 | True
40 |
--------------------------------------------------------------------------------
/source/c05/c05_28.md:
--------------------------------------------------------------------------------
1 | # 5.28 如何捕获警告?(注意不是捕获异常)
2 |
3 | ## 1. 警告不是异常
4 |
5 | 你是不是经常在使用一些系统库或者第三方模块的时候,会出现一些既不是异常也不是错误的警告信息?
6 |
7 | 这些警告信息,有时候非常多,对于新手容易造成一些误判,以为是程序出错了。
8 |
9 | 实则不然,异常和错误,都是程序出现了一些问题,但是警告不同,他的紧急程度非常之低,以致于大多数的警告都是可以直接忽略的。
10 |
11 | 如果不想显示这些告警信息,可以直接加上参数 `-W ignore` 参数,就不会再显示了。
12 |
13 | ## 2. 警告能捕获吗
14 |
15 | 能捕获的只有错误异常,但是通过一系列的操作后,你可以将这些警告转化为异常。
16 |
17 | 这样一来,你就可以像异常一样去捕获他们了。
18 |
19 | 在不进行任何设置的情况下,警告会直接打印在终端上。
20 |
21 | 
22 |
23 | ## 3. 捕获警告方法一
24 |
25 | 在 warnings 中有一系列的过滤器。
26 |
27 | | 值 | 处置 |
28 | | :---------- | :----------------------------------------------------- |
29 | | `"default"` | 为发出警告的每个位置(模块+行号)打印第一个匹配警告 |
30 | | `"error"` | 将匹配警告转换为异常 |
31 | | `"ignore"` | 从不打印匹配的警告 |
32 | | `"always"` | 总是打印匹配的警告 |
33 | | `"module"` | 为发出警告的每个模块打印第一次匹配警告(无论行号如何) |
34 | | `"once"` | 无论位置如何,仅打印第一次出现的匹配警告 |
35 |
36 | 当你指定为 error 的时候,就会将匹配警告转换为异常。
37 |
38 | 之后你就可以通过异常的方式去捕获警告了。
39 |
40 | ```python
41 | import warnings
42 | warnings.filterwarnings('error')
43 |
44 | try:
45 | warnings.warn("deprecated", DeprecationWarning)
46 | except Warning as e:
47 | print(e)
48 | ```
49 |
50 | 运行后,效果如下
51 |
52 | 
53 |
54 | ## 4. 捕获警告方法二
55 |
56 | 如果你不想对在代码中去配置将警告转成异常。
57 |
58 | ```python
59 | import warnings
60 |
61 | try:
62 | warnings.warn("deprecated", DeprecationWarning)
63 | except Warning as e:
64 | print(e)
65 | ```
66 |
67 | 可以在执行的时候,只要加上一个参数 `-W error` ,就可以实现一样的效果
68 |
69 | ```shell
70 | $ python3 -W error demo.py
71 | deprecated
72 | ```
73 |
74 | ## 5. 捕获警告方法三
75 |
76 | 除了上面的方法之外 ,warnings 还自带了个捕获警告的上下文管理器。
77 |
78 | 当你加上 `record=True` 它会返回一个列表,列表里存放的是所有捕获到的警告,我将它赋值为 `w`,然后就可以将它打印出来了。
79 |
80 | ```python
81 | import warnings
82 |
83 | def do_warning():
84 | warnings.warn("deprecated", DeprecationWarning)
85 |
86 | with warnings.catch_warnings(record=True) as w:
87 | do_warning()
88 | if len(w) >0:
89 | print(w[0].message)
90 | ```
91 |
92 | 运行后,效果如下
93 |
94 | 
--------------------------------------------------------------------------------
/source/c05/c05_29.md:
--------------------------------------------------------------------------------
1 | # 5.29 如何禁止对象深拷贝?
2 |
3 | 
4 |
5 | 当你使用 copy 模块的 deepcopy 拷贝一个对象后,会创建出来一个全新的的对象。
6 |
7 | ```python
8 | >>> from copy import deepcopy
9 | >>>
10 | >>> profile = {"name": "wangbm"}
11 | >>> id(profile)
12 | 21203408
13 | >>>
14 | >>> new_profile = deepcopy(profile)
15 | >>> id(new_profile)
16 | 21236144
17 | ```
18 |
19 | 但是有的时候,我们希望基于我们的类实例化后对象,禁止被深拷贝,这时候就要用到 Python 的魔法方法了。
20 |
21 | 在如下代码中,我们重写了 Sentinel 类的 `__deepcopy__` 和 `__copy__` 方法
22 |
23 | ```python
24 | class Sentinel(object):
25 | def __deepcopy__(self, memo):
26 | # Always return the same object because this is essentially a constant.
27 | return self
28 |
29 | def __copy__(self):
30 | # called via copy.copy(x)
31 | return self
32 | ```
33 |
34 | 此时你如果对它进行深度拷贝的话,会发现返回的永远都是原来的对象
35 |
36 | ```python
37 | >>> obj = Sentinel()
38 | >>> id(obj)
39 | 140151569169808
40 | >>>
41 | >>> new_obj = deepcopy(obj)
42 | >>> id(new_obj)
43 | 140151569169808
44 | ```
45 |
46 |
47 |
--------------------------------------------------------------------------------
/source/c05/c05_29.rst:
--------------------------------------------------------------------------------
1 | 5.29 如何禁止对象深拷贝?
2 | ========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 当你使用 copy 模块的 deepcopy
7 | 拷贝一个对象后,会创建出来一个全新的的对象。
8 |
9 | .. code:: python
10 |
11 | >>> from copy import deepcopy
12 | >>>
13 | >>> profile = {"name": "wangbm"}
14 | >>> id(profile)
15 | 21203408
16 | >>>
17 | >>> new_profile = deepcopy(profile)
18 | >>> id(new_profile)
19 | 21236144
20 |
21 | 但是有的时候,我们希望基于我们的类实例化后对象,禁止被深拷贝,这时候就要用到
22 | Python 的魔法方法了。
23 |
24 | 在如下代码中,我们重写了 Sentinel 类的 ``__deepcopy__`` 和 ``__copy__``
25 | 方法
26 |
27 | .. code:: python
28 |
29 | class Sentinel(object):
30 | def __deepcopy__(self, memo):
31 | # Always return the same object because this is essentially a constant.
32 | return self
33 |
34 | def __copy__(self):
35 | # called via copy.copy(x)
36 | return self
37 |
38 | 此时你如果对它进行深度拷贝的话,会发现返回的永远都是原来的对象
39 |
40 | .. code:: python
41 |
42 | >>> obj = Sentinel()
43 | >>> id(obj)
44 | 140151569169808
45 | >>>
46 | >>> new_obj = deepcopy(obj)
47 | >>> id(new_obj)
48 | 140151569169808
49 |
--------------------------------------------------------------------------------
/source/c05/c05_30.md:
--------------------------------------------------------------------------------
1 | # 5.30 如何将变量名和变量值转为字典?
2 |
3 | 
4 |
5 | 千言万语,不如上示例演示下效果
6 |
7 | ```python
8 | >>> name="wangbm"
9 | >>> age=28
10 | >>> gender="male"
11 | >>>
12 | >>> convert_vars_to_dict(name, age, gender)
13 | {'name': 'wangbm', 'age': 28, 'gender': 'male'}
14 | ```
15 |
16 | `convert_vars_to_dict` 是我要自己定义的这么一个函数,功能如上,代码如下。
17 |
18 | ```python
19 | import re
20 | import inspect
21 |
22 | def varname(*args):
23 | current_frame = inspect.currentframe()
24 | back_frame = current_frame.f_back
25 | back_frame_info = inspect.getframeinfo(back_frame)
26 |
27 | current_func_name = current_frame.f_code.co_name
28 |
29 | caller_file_path = back_frame_info[0]
30 | caller_line_no = back_frame_info[1]
31 | caller_type = back_frame_info[2]
32 | caller_expression = back_frame_info[3]
33 |
34 | keys = []
35 |
36 | for line in caller_expression:
37 | re_match = re.search(r'\b{}\((.*?)\)'.format(current_func_name), line)
38 | match_string = re_match.groups(1)[0]
39 | keys = [match.strip() for match in match_string.split(',') if match]
40 |
41 | return dict(zip(keys, args))
42 | ```
43 |
44 | 附上 :[inspect 学习文档](https://docs.python.org/zh-cn/3.7/library/inspect.html)
45 |
46 |
--------------------------------------------------------------------------------
/source/c05/c05_30.rst:
--------------------------------------------------------------------------------
1 | 5.30 如何将变量名和变量值转为字典?
2 | ===================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 千言万语,不如上示例演示下效果
7 |
8 | .. code:: python
9 |
10 | >>> name="wangbm"
11 | >>> age=28
12 | >>> gender="male"
13 | >>>
14 | >>> convert_vars_to_dict(name, age, gender)
15 | {'name': 'wangbm', 'age': 28, 'gender': 'male'}
16 |
17 | ``convert_vars_to_dict``
18 | 是我要自己定义的这么一个函数,功能如上,代码如下。
19 |
20 | .. code:: python
21 |
22 | import re
23 | import inspect
24 |
25 | def varname(*args):
26 | current_frame = inspect.currentframe()
27 | back_frame = current_frame.f_back
28 | back_frame_info = inspect.getframeinfo(back_frame)
29 |
30 | current_func_name = current_frame.f_code.co_name
31 |
32 | caller_file_path = back_frame_info[0]
33 | caller_line_no = back_frame_info[1]
34 | caller_type = back_frame_info[2]
35 | caller_expression = back_frame_info[3]
36 |
37 | keys = []
38 |
39 | for line in caller_expression:
40 | re_match = re.search(r'\b{}\((.*?)\)'.format(current_func_name), line)
41 | match_string = re_match.groups(1)[0]
42 | keys = [match.strip() for match in match_string.split(',') if match]
43 |
44 | return dict(zip(keys, args))
45 |
46 | 附上 :\ `inspect
47 | 学习文档 `__
48 |
--------------------------------------------------------------------------------
/source/c05/c05_31.md:
--------------------------------------------------------------------------------
1 | # 5.31 替换实例方法的最佳实践
2 |
3 | 
4 |
5 | ## 思路一:简单替换
6 |
7 | 当你想对类实例的方法进行替换时,你可能想到的是直接对他进行粗暴地替换
8 |
9 | ```python
10 | class People:
11 | def speak(self):
12 | print("hello, world")
13 |
14 |
15 | def speak(self):
16 | print("hello, python")
17 |
18 | p = People()
19 | p.speak = speak
20 | p.speak()
21 | ```
22 |
23 | 但当你试着执行这段代码的时候,就会发现行不通,它提示我们要传入 self 参数
24 |
25 | ```
26 | Traceback (most recent call last):
27 | File "/Users/MING/Code/Python/demo.py", line 12, in
28 | p.speak()
29 | TypeError: speak() missing 1 required positional argument: 'self'
30 | ```
31 |
32 | 不对啊~ self 不是实例本身吗?函数不是一直就这么写的?
33 |
34 | 实际上你这么替换,speak 就变成了一个 function,而不是一个和实例绑定的 method ,你可以把替换前后的 speak 打印出来
35 |
36 | ```python
37 | p = People()
38 | print(p.speak)
39 | p.speak = speak
40 | print(p.speak)
41 | ```
42 |
43 | 输出结果如下,区别非常明显
44 |
45 | ```
46 | >
47 |
48 | ```
49 |
50 | 这种方法,只能用在替换不与实例绑定的静态方法上,不然你每次调用的时候,就得手动传入实例本身,但这样调用就会变得非常怪异。
51 |
52 | ## 思路二:利用 im_func
53 |
54 | 有 Python 2 使用经验的朋友,可以会知道类实例的方法,都有 `im_func` 和 `im_class` 属性,分别指向了该方法的函数和类。
55 |
56 | 
57 |
58 | 很抱歉的是,这些在 Python3 中全都取消了,意味你无法再使用 `im_func` 和 `im_class` 。
59 |
60 | 但即使你身处 Python 2 的环境下,你想通过 `im_func` 去直接替换函数,也仍然是有问题的。
61 |
62 | 因为在 Python2 中不推荐普通用户对类实例的方法进行替换,所以 Python 给类实例的方法赋予了只读属性
63 |
64 | 
65 |
66 | ## 思路三:非常危险的字节码替换
67 |
68 | 表层不行,但这个方法在字节码层面却是可行的
69 |
70 | 
71 |
72 | 这种方法,非常的粗暴且危险,他会直接影响到使用 People 的所有实例的 speak 方法,因此这种方法千万不要使用。
73 |
74 | 
75 |
76 | ## 思路四:利用 types 绑定方法
77 |
78 | 在 types 中有一个 MethodType,可以将普通方法与实例进行绑定。
79 |
80 | 绑定后,就可以直接替换掉原实例的 speak 方法了,完整代码如下:
81 |
82 | ```python
83 | import types
84 |
85 | class People:
86 | def speak(self):
87 | print("hello, world")
88 |
89 |
90 | def speak(self):
91 | print("hello, python")
92 |
93 | p = People()
94 | p.speak = types.MethodType(speak, p)
95 | p.speak()
96 | ```
97 |
98 | 这种方法,最为安全,不会影响其他实例。并且 Python 2 和 Python 3 都适用,是官方推荐的一种做法。
99 |
100 |
--------------------------------------------------------------------------------
/source/c05/c05_32.md:
--------------------------------------------------------------------------------
1 | # 5.32 如何动态创建函数?
2 |
3 | 
4 |
5 | 在下面的代码中,每一次 for 循环都会创建一个返回特定字符串的函数。
6 |
7 | ```python
8 | from types import FunctionType
9 |
10 |
11 | for name in ("world", "python"):
12 | func = FunctionType(compile(
13 | ("def hello():\n"
14 | " return '{}'".format(name)),
15 | "",
16 | "exec").co_consts[0], globals())
17 |
18 | print(func())
19 | ```
20 |
21 | 输出如下
22 |
23 | ```
24 | world
25 | python
26 | ```
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/source/c05/c05_32.rst:
--------------------------------------------------------------------------------
1 | 5.32 如何动态创建函数?
2 | =======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在下面的代码中,每一次 for 循环都会创建一个返回特定字符串的函数。
7 |
8 | .. code:: python
9 |
10 | from types import FunctionType
11 |
12 |
13 | for name in ("world", "python"):
14 | func = FunctionType(compile(
15 | ("def hello():\n"
16 | " return '{}'".format(name)),
17 | "",
18 | "exec").co_consts[0], globals())
19 |
20 | print(func())
21 |
22 | 输出如下
23 |
24 | ::
25 |
26 | world
27 | python
28 |
--------------------------------------------------------------------------------
/source/c06/c06_01.md:
--------------------------------------------------------------------------------
1 | # 6.1 不要直接调用类的私有方法
2 | 
3 |
4 | 大家都知道,类中可供直接调用的方法,只有公有方法(protected类型的方法也可以,但是不建议)。也就是说,类的私有方法是无法直接调用的。
5 |
6 | 这里先看一下例子
7 |
8 | ```python
9 | class Kls():
10 | def public(self):
11 | print('Hello public world!')
12 |
13 | def __private(self):
14 | print('Hello private world!')
15 |
16 | def call_private(self):
17 | self.__private()
18 |
19 | ins = Kls()
20 |
21 | # 调用公有方法,没问题
22 | ins.public()
23 |
24 | # 直接调用私有方法,不行
25 | ins.__private()
26 |
27 | # 但你可以通过内部公有方法,进行代理
28 | ins.call_private()
29 | ```
30 |
31 | 既然都是方法,那我们真的没有办法可以直接调用吗?
32 |
33 | 当然有啦,只是建议你千万不要这样弄,这里只是普及,让你了解一下。
34 |
35 | ```python
36 | # 调用私有方法,以下两种等价
37 | ins._Kls__private()
38 | ins.call_private()
39 | ```
40 |
41 | ##
42 |
43 |
44 |
--------------------------------------------------------------------------------
/source/c06/c06_01.rst:
--------------------------------------------------------------------------------
1 | 6.1 不要直接调用类的私有方法
2 | ============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 大家都知道,类中可供直接调用的方法,只有公有方法(protected类型的方法也可以,但是不建议)。也就是说,类的私有方法是无法直接调用的。
7 |
8 | 这里先看一下例子
9 |
10 | .. code:: python
11 |
12 | class Kls():
13 | def public(self):
14 | print('Hello public world!')
15 |
16 | def __private(self):
17 | print('Hello private world!')
18 |
19 | def call_private(self):
20 | self.__private()
21 |
22 | ins = Kls()
23 |
24 | # 调用公有方法,没问题
25 | ins.public()
26 |
27 | # 直接调用私有方法,不行
28 | ins.__private()
29 |
30 | # 但你可以通过内部公有方法,进行代理
31 | ins.call_private()
32 |
33 | 既然都是方法,那我们真的没有办法可以直接调用吗?
34 |
35 | 当然有啦,只是建议你千万不要这样弄,这里只是普及,让你了解一下。
36 |
37 | .. code:: python
38 |
39 | # 调用私有方法,以下两种等价
40 | ins._Kls__private()
41 | ins.call_private()
42 |
--------------------------------------------------------------------------------
/source/c06/c06_02.md:
--------------------------------------------------------------------------------
1 | # 6.2 默认参数最好不为可变对象
2 | 
3 |
4 | 函数的参数分三种
5 |
6 | - 可变参数
7 | - 默认参数
8 | - 关键字参数
9 |
10 | 当你在传递默认参数时,有新手很容易踩雷的一个坑。
11 |
12 | 先来看一个示例
13 |
14 | ```python
15 | def func(item, item_list=[]):
16 | item_list.append(item)
17 | print(item_list)
18 |
19 | func('iphone')
20 | func('xiaomi', item_list=['oppo','vivo'])
21 | func('huawei')
22 | ```
23 |
24 | 在这里,你可以暂停一下,思考一下会输出什么?
25 |
26 | 思考过后,你的答案是否和下面的一致呢
27 |
28 | ```
29 | ['iphone']
30 | ['oppo', 'vivo', 'xiaomi']
31 | ['iphone', 'huawei']
32 | ```
33 |
34 | 如果是,那你可以跳过这部分内容,如果不是,请接着往下看,这里来分析一下。
35 |
36 | Python 中的 def 语句在每次执行的时候都初始化一个函数对象,这个函数对象就是我们要调用的函数,可以把它当成一个一般的对象,只不过这个对象拥有一个可执行的方法和部分属性。
37 |
38 | 对于参数中提供了初始值的参数,由于 Python 中的函数参数传递的是对象,也可以认为是传地址,在第一次初始化 def 的时候,会先生成这个可变对象的内存地址,然后将这个默认参数 item_list 会与这个内存地址绑定。在后面的函数调用中,如果调用方指定了新的默认值,就会将原来的默认值覆盖。如果调用方没有指定新的默认值,那就会使用原来的默认值。
39 |
40 | 
41 |
42 | ##
43 |
44 |
45 |
--------------------------------------------------------------------------------
/source/c06/c06_02.rst:
--------------------------------------------------------------------------------
1 | 6.2 默认参数最好不为可变对象
2 | ============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 函数的参数分三种
7 |
8 | - 可变参数
9 | - 默认参数
10 | - 关键字参数
11 |
12 | 当你在传递默认参数时,有新手很容易踩雷的一个坑。
13 |
14 | 先来看一个示例
15 |
16 | .. code:: python
17 |
18 | def func(item, item_list=[]):
19 | item_list.append(item)
20 | print(item_list)
21 |
22 | func('iphone')
23 | func('xiaomi', item_list=['oppo','vivo'])
24 | func('huawei')
25 |
26 | 在这里,你可以暂停一下,思考一下会输出什么?
27 |
28 | 思考过后,你的答案是否和下面的一致呢
29 |
30 | ::
31 |
32 | ['iphone']
33 | ['oppo', 'vivo', 'xiaomi']
34 | ['iphone', 'huawei']
35 |
36 | 如果是,那你可以跳过这部分内容,如果不是,请接着往下看,这里来分析一下。
37 |
38 | Python 中的 def
39 | 语句在每次执行的时候都初始化一个函数对象,这个函数对象就是我们要调用的函数,可以把它当成一个一般的对象,只不过这个对象拥有一个可执行的方法和部分属性。
40 |
41 | 对于参数中提供了初始值的参数,由于 Python
42 | 中的函数参数传递的是对象,也可以认为是传地址,在第一次初始化 def
43 | 的时候,会先生成这个可变对象的内存地址,然后将这个默认参数 item_list
44 | 会与这个内存地址绑定。在后面的函数调用中,如果调用方指定了新的默认值,就会将原来的默认值覆盖。如果调用方没有指定新的默认值,那就会使用原来的默认值。
45 |
46 | .. image:: http://image.iswbm.com/20190511165650.png
47 |
--------------------------------------------------------------------------------
/source/c06/c06_03.md:
--------------------------------------------------------------------------------
1 | # 6.3 增量赋值的性能更好
2 | 
3 |
4 | 诸如 `+=` 和 `*=` 这些运算符,叫做 增量赋值运算符。
5 |
6 | 这里使用用 += 举例,以下两种写法,在效果上是等价的。
7 |
8 | ```python
9 | # 第一种
10 | a = 1 ; a += 1
11 |
12 | # 第二种
13 | a = 1; a = a + 1
14 | ```
15 |
16 | `+=` 其背后使用的魔法方法是 `__iadd__`,如果没有实现这个方法则会退而求其次,使用 `__add__` 。
17 |
18 | 这两种写法有什么区别呢?
19 |
20 | 用列表举例 a += b,使用 `__add__` 的话就像是使用了a.extend(b),如果使用 `__add__` 的话,则是 a = a+b,前者是直接在原列表上进行扩展,而后者是先从原列表中取出值,在一个新的列表中进行扩展,然后再将新的列表对象返回给变量,显然后者的消耗要大些。
21 |
22 | 所以在能使用增量赋值的时候尽量使用它。
23 |
24 |
25 |
--------------------------------------------------------------------------------
/source/c06/c06_03.rst:
--------------------------------------------------------------------------------
1 | 6.3 增量赋值的性能更好
2 | ======================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 诸如 ``+=`` 和 ``*=`` 这些运算符,叫做 增量赋值运算符。
7 |
8 | 这里使用用 += 举例,以下两种写法,在效果上是等价的。
9 |
10 | .. code:: python
11 |
12 | # 第一种
13 | a = 1 ; a += 1
14 |
15 | # 第二种
16 | a = 1; a = a + 1
17 |
18 | ``+=`` 其背后使用的魔法方法是
19 | ``__iadd__``\ ,如果没有实现这个方法则会退而求其次,使用 ``__add__`` 。
20 |
21 | 这两种写法有什么区别呢?
22 |
23 | 用列表举例 a += b,使用 ``__add__`` 的话就像是使用了a.extend(b),如果使用
24 | ``__add__`` 的话,则是 a =
25 | a+b,前者是直接在原列表上进行扩展,而后者是先从原列表中取出值,在一个新的列表中进行扩展,然后再将新的列表对象返回给变量,显然后者的消耗要大些。
26 |
27 | 所以在能使用增量赋值的时候尽量使用它。
28 |
--------------------------------------------------------------------------------
/source/c06/c06_05.md:
--------------------------------------------------------------------------------
1 | # 6.5 变量名与保留关键字冲突怎么办?
2 |
3 | 
4 |
5 | 所有的编程语言都有一些保留关键字,这是代码得以编译/解释的基础。
6 |
7 | 有了这些关键字就组成了语法,当你的变量名和这些保留关键字冲突时,该怎么办呢?
8 |
9 | 在回答这个问题前,先要看看 Python 中的保留关键字有哪些?
10 |
11 | Python 的关键字,可以通过 keyword 这个模块列出来,一共有 33 个。
12 |
13 | ```python
14 | >>> import keyword;
15 | >>> print('\n'.join(keyword.kwlist))
16 | False
17 | None
18 | True
19 | and
20 | as
21 | assert
22 | break
23 | class
24 | continue
25 | def
26 | del
27 | elif
28 | else
29 | except
30 | finally
31 | for
32 | from
33 | global
34 | if
35 | import
36 | in
37 | is
38 | lambda
39 | nonlocal
40 | not
41 | or
42 | pass
43 | raise
44 | return
45 | try
46 | while
47 | with
48 | yield
49 | >>> len(keyword.kwlist)
50 | 33
51 | ```
52 |
53 | 使用这些关键字来做为变量名,是会报语法错误的。
54 |
55 | ```python
56 | >>> try = True
57 | File "", line 1
58 | try = True
59 | ^
60 | SyntaxError: invalid syntax
61 | ```
62 |
63 | 关于这个问题,[PEP8](https://www.python.org/dev/peps/pep-0008/) 建议当你想使用的变量名被关键字所占用时,可以使用 `变量_` 这样在变量后面加一个单下划线的形式来命名,这种后缀一下划线的方式优先于缩写或拼写错误。
64 |
65 | 
66 |
67 | 有了 PEP8 做为指导,我们可以这样子写了
68 |
69 | ```python
70 | >>> try_ = True
71 | ```
72 |
73 |
74 |
75 |
--------------------------------------------------------------------------------
/source/c06/c06_05.rst:
--------------------------------------------------------------------------------
1 | 6.5 变量名与保留关键字冲突怎么办?
2 | ==================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 所有的编程语言都有一些保留关键字,这是代码得以编译/解释的基础。
7 |
8 | 有了这些关键字就组成了语法,当你的变量名和这些保留关键字冲突时,该怎么办呢?
9 |
10 | 在回答这个问题前,先要看看 Python 中的保留关键字有哪些?
11 |
12 | Python 的关键字,可以通过 keyword 这个模块列出来,一共有 33 个。
13 |
14 | .. code:: python
15 |
16 | >>> import keyword;
17 | >>> print('\n'.join(keyword.kwlist))
18 | False
19 | None
20 | True
21 | and
22 | as
23 | assert
24 | break
25 | class
26 | continue
27 | def
28 | del
29 | elif
30 | else
31 | except
32 | finally
33 | for
34 | from
35 | global
36 | if
37 | import
38 | in
39 | is
40 | lambda
41 | nonlocal
42 | not
43 | or
44 | pass
45 | raise
46 | return
47 | try
48 | while
49 | with
50 | yield
51 | >>> len(keyword.kwlist)
52 | 33
53 |
54 | 使用这些关键字来做为变量名,是会报语法错误的。
55 |
56 | .. code:: python
57 |
58 | >>> try = True
59 | File "", line 1
60 | try = True
61 | ^
62 | SyntaxError: invalid syntax
63 |
64 | 关于这个问题,\ `PEP8 `__
65 | 建议当你想使用的变量名被关键字所占用时,可以使用 ``变量_``
66 | 这样在变量后面加一个单下划线的形式来命名,这种后缀一下划线的方式优先于缩写或拼写错误。
67 |
68 | .. image:: http://image.iswbm.com/20200823203106.png
69 |
70 | 有了 PEP8 做为指导,我们可以这样子写了
71 |
72 | .. code:: python
73 |
74 | >>> try_ = True
75 |
--------------------------------------------------------------------------------
/source/c06/c06_06.md:
--------------------------------------------------------------------------------
1 | # 6.6 不想让子类继承的变量名该怎么写?
2 |
3 | 
4 |
5 | 先来看下面这段代码
6 |
7 | ```python
8 | class Parent:
9 | def __init__(self):
10 | self.name = "MING"
11 |
12 | class Son(Parent):
13 | def __init__(self):
14 | self.name = "Xiao MING"
15 |
16 | bar = Son()
17 | print(bar.name)
18 | # 输出: Xiao MING
19 | ```
20 |
21 | Bar 作为 Foo 的子类,会继承父类的 name 属性。
22 |
23 | 如果有一些属性,是父类自己独有的,不想被子类继承,该怎么写呢?
24 |
25 | 可以在属性前面加两个下划线,两个类的定义如下
26 |
27 | ```python
28 | class Parent:
29 | def __init__(self):
30 | self.name = "MING"
31 | self.__wife = "Julia"
32 |
33 | class Son(Parent):
34 | def __init__(self):
35 | self.name = "Xiao MING"
36 | super().__init__()
37 | ```
38 |
39 | 从本章节的第一篇文章([6.1 不要直接调用类的私有方法](https://magic.iswbm.com/c06/c06_01.html))我们知道了私有的变量或函数,是不能直接调用的,需要用这样的形式才能访问 `_类名__变量名`。
40 |
41 | 从上面的代码中,可以看到 Son 类的实例并没有初始化 `__wife` 属性,虽然 Parent 类的实例有该属性,但由于这个属性是父类私有的,子类是无法访问的。因此当子类想要访问时,是会提示该变量不存在。
42 |
43 | 验证过程如下:
44 |
45 | 
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/source/c06/c06_06.rst:
--------------------------------------------------------------------------------
1 | 6.6 不想让子类继承的变量名该怎么写?
2 | ====================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 先来看下面这段代码
7 |
8 | .. code:: python
9 |
10 | class Parent:
11 | def __init__(self):
12 | self.name = "MING"
13 |
14 | class Son(Parent):
15 | def __init__(self):
16 | self.name = "Xiao MING"
17 |
18 | bar = Son()
19 | print(bar.name)
20 | # 输出: Xiao MING
21 |
22 | Bar 作为 Foo 的子类,会继承父类的 name 属性。
23 |
24 | 如果有一些属性,是父类自己独有的,不想被子类继承,该怎么写呢?
25 |
26 | 可以在属性前面加两个下划线,两个类的定义如下
27 |
28 | .. code:: python
29 |
30 | class Parent:
31 | def __init__(self):
32 | self.name = "MING"
33 | self.__wife = "Julia"
34 |
35 | class Son(Parent):
36 | def __init__(self):
37 | self.name = "Xiao MING"
38 | super().__init__()
39 |
40 | 从本章节的第一篇文章(\ `6.1
41 | 不要直接调用类的私有方法 `__\ )我们知道了私有的变量或函数,是不能直接调用的,需要用这样的形式才能访问
42 | ``_类名__变量名``\ 。
43 |
44 | 从上面的代码中,可以看到 Son 类的实例并没有初始化 ``__wife`` 属性,虽然
45 | Parent
46 | 类的实例有该属性,但由于这个属性是父类私有的,子类是无法访问的。因此当子类想要访问时,是会提示该变量不存在。
47 |
48 | 验证过程如下:
49 |
50 | .. image:: http://image.iswbm.com/20200823205210.png
51 |
--------------------------------------------------------------------------------
/source/c06/c06_07.md:
--------------------------------------------------------------------------------
1 | # 6.7 利用 any 代替 for 循环
2 |
3 | 
4 |
5 | 在某些场景下,我们需要判断是否满足某一组集合中任意一个条件
6 |
7 | 这时候,很多同学自然会想到使用 for 循环。
8 |
9 | ```python
10 | found = False
11 | for thing in things:
12 | if thing == other_thing:
13 | found = True
14 | break
15 | ```
16 |
17 | 但其实更好的写法,是使用 `any()` 函数,能够使这段代码变得更加清晰、简洁
18 |
19 | ```python
20 | found = any(thing == other_thing for thing in things)
21 | ```
22 |
23 | 使用 any 并不会减少 for 循环的次数,只要有一个条件为 True,any 就能得到结果。
24 |
25 | 同理,当你需要判断是否满足某一组集合中所有条件,也可以使用 `all()` 函数。
26 |
27 | ```python
28 | found = all(thing == other_thing for thing in things)
29 | ```
30 |
31 | 只要有一个不满足条件,all 函数的结果就会立刻返回 False
32 |
33 |
34 |
35 |
--------------------------------------------------------------------------------
/source/c06/c06_07.rst:
--------------------------------------------------------------------------------
1 | 6.7 利用 any 代替 for 循环
2 | ==========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在某些场景下,我们需要判断是否满足某一组集合中任意一个条件
7 |
8 | 这时候,很多同学自然会想到使用 for 循环。
9 |
10 | .. code:: python
11 |
12 | found = False
13 | for thing in things:
14 | if thing == other_thing:
15 | found = True
16 | break
17 |
18 | 但其实更好的写法,是使用 ``any()``
19 | 函数,能够使这段代码变得更加清晰、简洁
20 |
21 | .. code:: python
22 |
23 | found = any(thing == other_thing for thing in things)
24 |
25 | 使用 any 并不会减少 for 循环的次数,只要有一个条件为 True,any
26 | 就能得到结果。
27 |
28 | 同理,当你需要判断是否满足某一组集合中所有条件,也可以使用 ``all()``
29 | 函数。
30 |
31 | .. code:: python
32 |
33 | found = all(thing == other_thing for thing in things)
34 |
35 | 只要有一个不满足条件,all 函数的结果就会立刻返回 False
36 |
--------------------------------------------------------------------------------
/source/c06/c06_08.md:
--------------------------------------------------------------------------------
1 | # 6.8 不同条件分支里应减少重合度
2 |
3 | 
4 |
5 | 如下是一个简单的条件语句模型
6 |
7 | ```python
8 | if A:
9 |
10 | elif B:
11 |
12 | else:
13 |
14 | ```
15 |
16 | 如果 code_block_2 和 code_block_1 的代码完全一致,那么应该想办法减少代码冗余。
17 |
18 | 这边举个例子,下面这段代码中
19 |
20 | ```python
21 | def process_payment(payment):
22 | if payment.currency == 'USD':
23 | process_standard_payment(payment)
24 | elif payment.currency == 'EUR':
25 | process_standard_payment(payment)
26 | else:
27 | process_international_payment(payment)
28 | ```
29 |
30 | 其实更好的做法是用 in 来合并条件一和条件二
31 |
32 | ```python
33 | def process_payment(payment):
34 | if payment.currency in ('USD', 'EUR'):
35 | process_standard_payment(payment)
36 | else:
37 | process_international_payment(payment)
38 | ```
39 |
40 |
41 |
42 |
--------------------------------------------------------------------------------
/source/c06/c06_08.rst:
--------------------------------------------------------------------------------
1 | 6.8 不同条件分支里应减少重合度
2 | ==============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 如下是一个简单的条件语句模型
7 |
8 | .. code:: python
9 |
10 | if A:
11 |
12 | elif B:
13 |
14 | else:
15 |
16 |
17 | 如果 code_block_2 和 code_block_1
18 | 的代码完全一致,那么应该想办法减少代码冗余。
19 |
20 | 这边举个例子,下面这段代码中
21 |
22 | .. code:: python
23 |
24 | def process_payment(payment):
25 | if payment.currency == 'USD':
26 | process_standard_payment(payment)
27 | elif payment.currency == 'EUR':
28 | process_standard_payment(payment)
29 | else:
30 | process_international_payment(payment)
31 |
32 | 其实更好的做法是用 in 来合并条件一和条件二
33 |
34 | .. code:: python
35 |
36 | def process_payment(payment):
37 | if payment.currency in ('USD', 'EUR'):
38 | process_standard_payment(payment)
39 | else:
40 | process_international_payment(payment)
41 |
--------------------------------------------------------------------------------
/source/c06/c06_09.md:
--------------------------------------------------------------------------------
1 | # 6.9 如无必要,勿增实体噢
2 |
3 | 
4 |
5 | ## 删除没必要的调用`keys()`
6 |
7 | 字典是由一个个的键值对组成的,如果你遍历字典时只需要访问键,用不到值,有很多同学会用下面这种方式:
8 |
9 | ```python
10 | for currency in currencies.keys():
11 | process(currency)
12 | ```
13 |
14 | 在这种情况下,不需要调用keys(),因为遍历字典时的默认行为是遍历键。
15 |
16 | ```python
17 | for currency in currencies:
18 | process(currency)
19 | ```
20 |
21 | 现在,该代码更加简洁,易于阅读,并且避免调用函数会带来性能改进。
22 |
23 | ## 简化序列比较
24 |
25 | 我们经常要做的是在尝试对列表或序列进行操作之前检查列表或序列是否包含元素。
26 |
27 | ```python
28 | if len(list_of_hats) > 0:
29 | hat_to_wear = choose_hat(list_of_hats)
30 | ```
31 |
32 | 使用Python的方法则更加简单:如果Python列表和序列具有元素,则返回为True,否则为False:
33 |
34 | ```python
35 | if list_of_hats:
36 | hat_to_wear = choose_hat(list_of_hats)
37 | ```
38 |
39 | ## 仅使用一次的内联变量
40 |
41 | 我们在很多代码中经常看到,有些同学分配结果给变量,然后马上返回它,例如,
42 |
43 | ```python
44 | def state_attributes(self):
45 | """Return the state attributes."""
46 | state_attr = {
47 | ATTR_CODE_FORMAT: self.code_format,
48 | ATTR_CHANGED_BY: self.changed_by,
49 | }
50 | return state_attr
51 | ```
52 |
53 | 如果直接返回,则更加直观、简洁,
54 |
55 | ```python
56 | def state_attributes(self):
57 | """Return the state attributes."""
58 | return {
59 | ATTR_CODE_FORMAT: self.code_format,
60 | ATTR_CHANGED_BY: self.changed_by,
61 | }
62 | ```
63 |
64 | 这样可以缩短代码并删除不必要的变量,从而减轻了读取函数的负担。
65 |
66 |
67 |
68 |
--------------------------------------------------------------------------------
/source/c06/c06_09.rst:
--------------------------------------------------------------------------------
1 | 6.9 如无必要,勿增实体噢
2 | ========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 删除没必要的调用\ ``keys()``
7 | ----------------------------
8 |
9 | 字典是由一个个的键值对组成的,如果你遍历字典时只需要访问键,用不到值,有很多同学会用下面这种方式:
10 |
11 | .. code:: python
12 |
13 | for currency in currencies.keys():
14 | process(currency)
15 |
16 | 在这种情况下,不需要调用keys(),因为遍历字典时的默认行为是遍历键。
17 |
18 | .. code:: python
19 |
20 | for currency in currencies:
21 | process(currency)
22 |
23 | 现在,该代码更加简洁,易于阅读,并且避免调用函数会带来性能改进。
24 |
25 | 简化序列比较
26 | ------------
27 |
28 | 我们经常要做的是在尝试对列表或序列进行操作之前检查列表或序列是否包含元素。
29 |
30 | .. code:: python
31 |
32 | if len(list_of_hats) > 0:
33 | hat_to_wear = choose_hat(list_of_hats)
34 |
35 | 使用Python的方法则更加简单:如果Python列表和序列具有元素,则返回为True,否则为False:
36 |
37 | .. code:: python
38 |
39 | if list_of_hats:
40 | hat_to_wear = choose_hat(list_of_hats)
41 |
42 | 仅使用一次的内联变量
43 | --------------------
44 |
45 | 我们在很多代码中经常看到,有些同学分配结果给变量,然后马上返回它,例如,
46 |
47 | .. code:: python
48 |
49 | def state_attributes(self):
50 | """Return the state attributes."""
51 | state_attr = {
52 | ATTR_CODE_FORMAT: self.code_format,
53 | ATTR_CHANGED_BY: self.changed_by,
54 | }
55 | return state_attr
56 |
57 | 如果直接返回,则更加直观、简洁,
58 |
59 | .. code:: python
60 |
61 | def state_attributes(self):
62 | """Return the state attributes."""
63 | return {
64 | ATTR_CODE_FORMAT: self.code_format,
65 | ATTR_CHANGED_BY: self.changed_by,
66 | }
67 |
68 | 这样可以缩短代码并删除不必要的变量,从而减轻了读取函数的负担。
69 |
--------------------------------------------------------------------------------
/source/c06/c06_10.md:
--------------------------------------------------------------------------------
1 | # 6.10 保持代码的简洁与可诗性
2 |
3 | 
4 |
5 | ## 将条件简化为return语句
6 |
7 | 如果,我们实现的函数要返回一个布尔型的结果,通常会这样去做,
8 |
9 | ```python
10 | def function():
11 | if isinstance(a, b) or issubclass(b, a):
12 | returnTrue
13 | returnFalse
14 | ```
15 |
16 | 但是,对比这样,直接返回结果会更加明智:
17 |
18 | ```python
19 | def function():
20 | return isinstance(a, b) or issubclass(b, a)
21 | ```
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/source/c06/c06_10.rst:
--------------------------------------------------------------------------------
1 | 6.10 保持代码的简洁与可诗性
2 | ===========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 将条件简化为return语句
7 | ----------------------
8 |
9 | 如果,我们实现的函数要返回一个布尔型的结果,通常会这样去做,
10 |
11 | .. code:: python
12 |
13 | def function():
14 | if isinstance(a, b) or issubclass(b, a):
15 | returnTrue
16 | returnFalse
17 |
18 | 但是,对比这样,直接返回结果会更加明智:
19 |
20 | .. code:: python
21 |
22 | def function():
23 | return isinstance(a, b) or issubclass(b, a)
24 |
--------------------------------------------------------------------------------
/source/c06/c06_11.md:
--------------------------------------------------------------------------------
1 | # 6.11 给模块的私有属性上保险
2 |
3 | 
4 |
5 | ## 保护对象
6 |
7 | 有的朋友,喜欢简单粗暴的使用 `from x import *` 来导入 x 模块中的所有对象,实际上有一些对象或者变量,是实现细节,不需要暴露给导入方的,因为导入了也用不上。
8 |
9 | 对于这些变量或者对象,就可以在前面其名字前加上下划线,只要在变量名前加上下划线,就属于 "保护对象"。
10 |
11 | 使用 `from x import *` 后,这些 "保护对象" 是会直接跳过导入。
12 |
13 | 比如下面这些代码中,只有 drive 函数才会被 `from x import *` 所导入
14 |
15 | ```python
16 | _moto_type = 'L15b2'
17 | _wheel_type = 'michelin'
18 |
19 | def drive():
20 | _start_engine()
21 | _drive_wheel()
22 |
23 | def _start_engine():
24 | print('start engine %s'%_moto_type)
25 |
26 | def _drive_wheel():
27 | print('drive wheel %s'%_wheel_type)
28 | ```
29 |
30 | ## 突破保护
31 |
32 | 前面之所以说是“保护”并不是“私有”,是因为Python没有提供解释器机制来控制访问权限。我们依然可以访问这些属性:
33 |
34 | ```python
35 | import tools
36 | tools._moto_type = 'EA211'
37 | tools.drive()
38 | ```
39 |
40 | 以上代码,以越过“保护属性”。此外,还有两种方法能突破这个限制,一种是将“私有属性”添加到tool.py文件的`__all__`列表里,使`from tools import *`也导入这些本该隐藏的属性。
41 |
42 | ```python
43 | __all__ = ['drive','_moto_type','_wheel_type']
44 | ```
45 |
46 | 另一种是导入时指定“受保护属性”名。
47 |
48 | ```python
49 | from tools import drive,_start_engine
50 | _start_engine()
51 | ```
52 |
53 | 甚至是,使用`import tools`也可以轻易突破保护限制。所以可见,“保护属性”是一种简单的隐藏机制,只有在`from tools import *`时,由解释器提供简单的保护,但是可以轻易突破。这种保护更多地依赖程序员的共识:不访问、修改“保护属性”。除此之外,有没有更安全的保护机制呢?有,就是下一部分讨论的私有变量。
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/source/c06/c06_11.rst:
--------------------------------------------------------------------------------
1 | 6.11 给模块的私有属性上保险
2 | ===========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 保护对象
7 | --------
8 |
9 | 有的朋友,喜欢简单粗暴的使用 ``from x import *`` 来导入 x
10 | 模块中的所有对象,实际上有一些对象或者变量,是实现细节,不需要暴露给导入方的,因为导入了也用不上。
11 |
12 | 对于这些变量或者对象,就可以在前面其名字前加上下划线,只要在变量名前加上下划线,就属于
13 | “保护对象”。
14 |
15 | 使用 ``from x import *`` 后,这些 “保护对象” 是会直接跳过导入。
16 |
17 | 比如下面这些代码中,只有 drive 函数才会被 ``from x import *`` 所导入
18 |
19 | .. code:: python
20 |
21 | _moto_type = 'L15b2'
22 | _wheel_type = 'michelin'
23 |
24 | def drive():
25 | _start_engine()
26 | _drive_wheel()
27 |
28 | def _start_engine():
29 | print('start engine %s'%_moto_type)
30 |
31 | def _drive_wheel():
32 | print('drive wheel %s'%_wheel_type)
33 |
34 | 突破保护
35 | --------
36 |
37 | 前面之所以说是“保护”并不是“私有”,是因为Python没有提供解释器机制来控制访问权限。我们依然可以访问这些属性:
38 |
39 | .. code:: python
40 |
41 | import tools
42 | tools._moto_type = 'EA211'
43 | tools.drive()
44 |
45 | 以上代码,以越过“保护属性”。此外,还有两种方法能突破这个限制,一种是将“私有属性”添加到tool.py文件的\ ``__all__``\ 列表里,使\ ``from tools import *``\ 也导入这些本该隐藏的属性。
46 |
47 | .. code:: python
48 |
49 | __all__ = ['drive','_moto_type','_wheel_type']
50 |
51 | 另一种是导入时指定“受保护属性”名。
52 |
53 | .. code:: python
54 |
55 | from tools import drive,_start_engine
56 | _start_engine()
57 |
58 | 甚至是,使用\ ``import tools``\ 也可以轻易突破保护限制。所以可见,“保护属性”是一种简单的隐藏机制,只有在\ ``from tools import *``\ 时,由解释器提供简单的保护,但是可以轻易突破。这种保护更多地依赖程序员的共识:不访问、修改“保护属性”。除此之外,有没有更安全的保护机制呢?有,就是下一部分讨论的私有变量。
59 |
--------------------------------------------------------------------------------
/source/c06/c06_12.md:
--------------------------------------------------------------------------------
1 | # 6.12 变量不能与保留关键字重名
2 |
3 | 
4 |
5 | 在 Python 中有很多的保留关键字,这些关键字的使用,不需要我们定义,也不需要我们导入,只要你进入到了 Python 的环境中,就可以立即使用。
6 |
7 | 使用如下方法,可以查看 Python 中的保留关键字
8 |
9 | ```python
10 | >>> import keyword
11 | >>> keyword.kwlist
12 | ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']
13 | ```
14 |
15 | 而很尴尬的是,如果你在日常编码中,不经意地用到其中的一些关键字,就会产生冲突。
16 |
17 | 比如说 class,这个有类别的意思,可能你也想使用它来作为变量名,如果直接使用,会发生冲突
18 |
19 | 更好的做法是,使用下划线来避免冲突
20 |
21 | ```python
22 | def type_obj_class(name,class_):
23 | pass
24 |
25 | def tag(name,*content,class_):
26 | pass
27 | ```
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/source/c06/c06_12.rst:
--------------------------------------------------------------------------------
1 | 6.12 变量不能与保留关键字重名
2 | =============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在 Python
7 | 中有很多的保留关键字,这些关键字的使用,不需要我们定义,也不需要我们导入,只要你进入到了
8 | Python 的环境中,就可以立即使用。
9 |
10 | 使用如下方法,可以查看 Python 中的保留关键字
11 |
12 | .. code:: python
13 |
14 | >>> import keyword
15 | >>> keyword.kwlist
16 | ['and', 'as', 'assert', 'break', 'class', 'continue', 'def', 'del', 'elif', 'else', 'except', 'exec', 'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'is', 'lambda', 'not', 'or', 'pass', 'print', 'raise', 'return', 'try', 'while', 'with', 'yield']
17 |
18 | 而很尴尬的是,如果你在日常编码中,不经意地用到其中的一些关键字,就会产生冲突。
19 |
20 | 比如说
21 | class,这个有类别的意思,可能你也想使用它来作为变量名,如果直接使用,会发生冲突
22 |
23 | 更好的做法是,使用下划线来避免冲突
24 |
25 | .. code:: python
26 |
27 | def type_obj_class(name,class_):
28 | pass
29 |
30 | def tag(name,*content,class_):
31 | pass
32 |
--------------------------------------------------------------------------------
/source/c07/c07_08.md:
--------------------------------------------------------------------------------
1 | # 7.8 像操作路径一样,操作嵌套字典
2 |
3 | 
4 |
5 | 在使用前先安装它,要注意的是该模块只能在 Python 3.8+ 中使用
6 |
7 | ```shell
8 | $ python3 -m pip install dpath
9 | ```
10 |
11 | 下边是一个简单的使用案例
12 |
13 | ```python
14 | import dpath.util
15 |
16 | data = {
17 | "foo": {
18 | "bar": {
19 | "a": 10,
20 | "b": 20,
21 | "c": [],
22 | "d": ['red', 'buggy', 'bumpers'],
23 | }
24 | }
25 | }
26 |
27 | print(dpath.util.get(data, "/foo/bar/d"))
28 | ```
29 |
30 | 使用 `[ab]` 会把 键为 `a` 和 `b` 的都筛选出来
31 |
32 | ```python
33 | print(dpath.util.search(data, "/foo/bar/[ab]"))
34 | # output: {'foo': {'bar': {'a': 10, 'b': 20}}}
35 | ```
36 |
37 | 获取所有匹配的键值对的 value 值列表
38 |
39 | ```python
40 | print(dpath.util.values(data, "/foo/bar/*"))
41 | # output: [10, 20, [], ['red', 'buggy', 'bumpers']]
42 | ```
43 |
44 |
45 |
46 | 更多案例,请前往 [官方文档](https://pypi.org/project/dpath/) 查阅。
47 |
48 |
49 |
50 |
--------------------------------------------------------------------------------
/source/c07/c07_08.rst:
--------------------------------------------------------------------------------
1 | 7.8 像操作路径一样,操作嵌套字典
2 | ================================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 在使用前先安装它,要注意的是该模块只能在 Python 3.8+ 中使用
7 |
8 | .. code:: shell
9 |
10 | $ python3 -m pip install dpath
11 |
12 | 下边是一个简单的使用案例
13 |
14 | .. code:: python
15 |
16 | import dpath.util
17 |
18 | data = {
19 | "foo": {
20 | "bar": {
21 | "a": 10,
22 | "b": 20,
23 | "c": [],
24 | "d": ['red', 'buggy', 'bumpers'],
25 | }
26 | }
27 | }
28 |
29 | print(dpath.util.get(data, "/foo/bar/d"))
30 |
31 | 使用 ``[ab]`` 会把 键为 ``a`` 和 ``b`` 的都筛选出来
32 |
33 | .. code:: python
34 |
35 | print(dpath.util.search(data, "/foo/bar/[ab]"))
36 | # output: {'foo': {'bar': {'a': 10, 'b': 20}}}
37 |
38 | 获取所有匹配的键值对的 value 值列表
39 |
40 | .. code:: python
41 |
42 | print(dpath.util.values(data, "/foo/bar/*"))
43 | # output: [10, 20, [], ['red', 'buggy', 'bumpers']]
44 |
45 | 更多案例,请前往 `官方文档 `__ 查阅。
46 |
--------------------------------------------------------------------------------
/source/c07/c07_09.md:
--------------------------------------------------------------------------------
1 | # 7.9 读取文件中任意行的数据
2 |
3 | 
4 |
5 | `linecache` 是 Python 中的一个内置模块。
6 |
7 | 它允许从任何文件中获取任意行,同时尝试使用缓存进行内部优化,这是一种常见的情况,即从单个文件读取多行。它被`traceback`模块用来检索包含在格式化回溯中的源代码行。
8 |
9 | 这是一个简单的例子。
10 |
11 | ```python
12 | >>> import linecache
13 | >>> linecache.getline('/etc/passwd', 4)
14 | 'sys:x:3:3:sys:/dev:/bin/sh\n'
15 | ```
16 |
17 | 如果你指定的行数超过了文件原有的行数,该函数也不会抛出错误,而是返回空字符串。
18 |
19 | ```python
20 | >>> import linecache
21 | >>> linecache.getline('/etc/passwd', 10000)
22 |
23 | >>>
24 | ```
25 |
26 |
--------------------------------------------------------------------------------
/source/c07/c07_09.rst:
--------------------------------------------------------------------------------
1 | 7.9 读取文件中任意行的数据
2 | ==========================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | ``linecache`` 是 Python 中的一个内置模块。
7 |
8 | 它允许从任何文件中获取任意行,同时尝试使用缓存进行内部优化,这是一种常见的情况,即从单个文件读取多行。它被\ ``traceback``\ 模块用来检索包含在格式化回溯中的源代码行。
9 |
10 | 这是一个简单的例子。
11 |
12 | .. code:: python
13 |
14 | >>> import linecache
15 | >>> linecache.getline('/etc/passwd', 4)
16 | 'sys:x:3:3:sys:/dev:/bin/sh\n'
17 |
18 | 如果你指定的行数超过了文件原有的行数,该函数也不会抛出错误,而是返回空字符串。
19 |
20 | .. code:: python
21 |
22 | >>> import linecache
23 | >>> linecache.getline('/etc/passwd', 10000)
24 |
25 | >>>
26 |
--------------------------------------------------------------------------------
/source/c07/c07_11.md:
--------------------------------------------------------------------------------
1 | # 7.11 国际化模块,让翻译更优雅
2 |
3 | 
4 |
5 | ## 国际化与本地化
6 |
7 | 国际化 (internationalization),简称 **i18n**
8 |
9 | 很多人并不知道,为什么要叫 i18n 呢?怎么谐音都不对。
10 |
11 | 实际上 18 是指在 ”internationalization” 这个单词中,i 和 n之间有18个字母。
12 |
13 |
14 |
15 | 而与之相对的,本地化(localization),简称 L10 n,10 就是指在 ”localization”这个单词中,l 和 n 之间有10个字母
16 |
17 | 本地化是指使一个国际化的软件为了在某个特定地区使用而进行实际翻译的过程。
18 |
19 | 国际化的软件具备这样一种能力,当软件被移植到不同的语言及地区时,软件本身不用做内部工程上的改变或修正。
20 |
21 | ## gettext 模块
22 |
23 | gettext 是一套 GNU下的国际化工具。主要有工具:
24 |
25 | - xgettext: 从源码中抽取字符串,生成po文件(portable object)
26 | - msgfmt: 将po文件编译成mo文件(machine object)
27 | - gettext: 进行翻译,如果找不到gettext命令,或者找不到msgfmt命令。请重新安装一遍gettext套件。
28 |
29 |
30 | 很多系统中都内置了 gettext 模块
31 |
32 | 如果你在 ubuntu系统中,可能需要如下命令进行安装
33 |
34 | ```
35 | sudo apt-get install gettext
36 | ```
37 |
38 | ## 简单示例演示
39 |
40 | 首先新建一个目录
41 |
42 | ```shell
43 | $ mkdir -p locale/zh_CN/LC_MESSAGES
44 | ```
45 |
46 | 然后在这个目录下新建一个 `hello.po` 文件
47 |
48 | ```
49 | msgid "hello world"
50 | msgstr "你好世界"
51 | ```
52 |
53 | 然后执行如下一条命令,将 po 文件翻译成 mo文件
54 |
55 | ```shell
56 | $ msgfmt locale/zh_CN/LC_MESSAGES/hello.po -o locale/zh_CN/LC_MESSAGES/hello.mo
57 | ```
58 |
59 | 然后在 local 同级目录下进入 Console 模式,就可以使用 `_` 进行翻译了,为什么 `_` 能这么用,原因是 `zh.install() ` 这个调用将其绑定到了 Python 内建命名空间中,以便在应用程序的所有模块中轻松访问它。
60 |
61 | ```python
62 | >>> import gettext
63 | >>> zh = gettext.translation("hello", "locale", languages=["zh_CN"])
64 | >>> zh.install()
65 | >>> _('hello world')
66 | '你好世界'
67 | ```
68 |
69 |
70 |
71 |
--------------------------------------------------------------------------------
/source/c07/c07_11.rst:
--------------------------------------------------------------------------------
1 | 7.11 国际化模块,让翻译更优雅
2 | =============================
3 |
4 | .. image:: http://image.iswbm.com/20200804124133.png
5 |
6 | 国际化与本地化
7 | --------------
8 |
9 | 国际化 (internationalization),简称 **i18n**
10 |
11 | 很多人并不知道,为什么要叫 i18n 呢?怎么谐音都不对。
12 |
13 | 实际上 18 是指在 ”internationalization” 这个单词中,i 和
14 | n之间有18个字母。
15 |
16 | 而与之相对的,本地化(localization),简称 L10 n,10 就是指在
17 | ”localization”这个单词中,l 和 n 之间有10个字母
18 |
19 | 本地化是指使一个国际化的软件为了在某个特定地区使用而进行实际翻译的过程。
20 |
21 | 国际化的软件具备这样一种能力,当软件被移植到不同的语言及地区时,软件本身不用做内部工程上的改变或修正。
22 |
23 | gettext 模块
24 | ------------
25 |
26 | gettext 是一套 GNU下的国际化工具。主要有工具:
27 |
28 | - xgettext: 从源码中抽取字符串,生成po文件(portable object)
29 | - msgfmt: 将po文件编译成mo文件(machine object)
30 | - gettext:
31 | 进行翻译,如果找不到gettext命令,或者找不到msgfmt命令。请重新安装一遍gettext套件。
32 |
33 | 很多系统中都内置了 gettext 模块
34 |
35 | 如果你在 ubuntu系统中,可能需要如下命令进行安装
36 |
37 | ::
38 |
39 | sudo apt-get install gettext
40 |
41 | 简单示例演示
42 | ------------
43 |
44 | 首先新建一个目录
45 |
46 | .. code:: shell
47 |
48 | $ mkdir -p locale/zh_CN/LC_MESSAGES
49 |
50 | 然后在这个目录下新建一个 ``hello.po`` 文件
51 |
52 | ::
53 |
54 | msgid "hello world"
55 | msgstr "你好世界"
56 |
57 | 然后执行如下一条命令,将 po 文件翻译成 mo文件
58 |
59 | .. code:: shell
60 |
61 | $ msgfmt locale/zh_CN/LC_MESSAGES/hello.po -o locale/zh_CN/LC_MESSAGES/hello.mo
62 |
63 | 然后在 local 同级目录下进入 Console 模式,就可以使用 ``_``
64 | 进行翻译了,为什么 ``_`` 能这么用,原因是 ``zh.install()``
65 | 这个调用将其绑定到了 Python
66 | 内建命名空间中,以便在应用程序的所有模块中轻松访问它。
67 |
68 | .. code:: python
69 |
70 | >>> import gettext
71 | >>> zh = gettext.translation("hello", "locale", languages=["zh_CN"])
72 | >>> zh.install()
73 | >>> _('hello world')
74 | '你好世界'
75 |
--------------------------------------------------------------------------------
/source/chapters/p01.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | 第一章:魔法冷知识
3 | =============================
4 |
5 | 这个章节记录了一些大多数开发者并不知晓的冷知识,内容基本延续 v1.0 。
6 |
7 | 本章节,会持续更新,敬请关注...
8 |
9 | ---------------------------
10 |
11 |
12 | .. toctree::
13 | :maxdepth: 1
14 | :glob:
15 |
16 | ../c01/*
17 |
18 |
19 |
--------------------------------------------------------------------------------
/source/chapters/p02.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | 第二章:魔法命令行
3 | =============================
4 |
5 | 这个章节是全新的内容,主要介绍的是 Python Shell 的一些冷门玩法,这里面的内容,应该足够让你惊叹。
6 |
7 | -------------------
8 |
9 | .. toctree::
10 | :maxdepth: 1
11 | :glob:
12 |
13 | ../c02/*
14 |
15 |
16 |
--------------------------------------------------------------------------------
/source/chapters/p03.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | 第三章:炫技魔法操作
3 | =============================
4 |
5 | 这个章节是取自我个人公众号原创专辑《Python炫技操作》里的文章,其中的多篇文章成为了爆款文章,不少大号均有转载。很多网友看完后直呼 "卧槽,居然还能这样?!",如果你之前没有看过这几篇文章,那么你读这一章一定会大有收获。
6 |
7 | 本章节,会持续更新,敬请关注…
8 |
9 | -------------------------
10 |
11 | .. toctree::
12 | :maxdepth: 1
13 | :glob:
14 |
15 | ../c03/*
16 |
17 |
18 |
--------------------------------------------------------------------------------
/source/chapters/p04.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | 第四章:魔法进阶扫盲
3 | =============================
4 |
5 | 这一章节主要深入理解 Python 中那些难点,将这些难点逐个击破?
6 |
7 | 比如:
8 |
9 | 如何写出一个可以带参数的装饰器呢?
10 |
11 | 装饰器可以装饰函数,那么你知道如何装饰类吗?
12 |
13 | 描述符的访问规则是什么?
14 |
15 | 描述符在实际开发中有哪些使用场景?
16 |
17 | 这些恐怕有不少人都还没有深入学习过,这一章节可扩展的内容有很多,比如元类等,日后会慢慢完善。
18 |
19 | ----------------------------
20 |
21 | .. toctree::
22 | :maxdepth: 1
23 | :glob:
24 |
25 | ../c04/*
26 |
27 |
28 |
--------------------------------------------------------------------------------
/source/chapters/p05.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | 第五章:魔法开发技巧
3 | =============================
4 |
5 | 这个章节可能会是很多人感兴趣的,因为里面介绍的是所有开发者都有可能用到的开发技巧,掌握这些代码编写技巧,对提高你代码的可读性、优雅性会很有帮助。
6 |
7 | 本章节,会持续更新,敬请关注…
8 |
9 | ----------------------------
10 |
11 | .. toctree::
12 | :maxdepth: 1
13 | :glob:
14 |
15 | ../c05/*
16 |
17 |
18 |
--------------------------------------------------------------------------------
/source/chapters/p06.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | 第六章:良好编码习惯
3 | =============================
4 |
5 | 这个章节会写一些我自己日常开发总结的一些开发习惯,虽然内容还不是很多,但是我已经有了很多的思路,大家再给我点时间。
6 |
7 | 本章节,会持续更新,敬请关注…
8 |
9 | ----------------------------
10 |
11 | .. toctree::
12 | :maxdepth: 1
13 | :glob:
14 |
15 | ../c06/*
16 |
17 |
18 |
--------------------------------------------------------------------------------
/source/chapters/p07.rst:
--------------------------------------------------------------------------------
1 | =============================
2 | 第七章:神奇魔法模块
3 | =============================
4 |
5 | 这个章节会收集一些被市场公认好用的模块,对于编码代码很有帮助,同样还是需要时间慢慢沉淀。
6 |
7 | 本章节,会持续更新,敬请关注…
8 |
9 | ----------------------------
10 |
11 | .. toctree::
12 | :maxdepth: 1
13 | :glob:
14 |
15 | ../c07/*
16 |
17 |
18 |
--------------------------------------------------------------------------------
/source/index.rst:
--------------------------------------------------------------------------------
1 | .. python-time documentation master file, created by
2 | sphinx-quickstart on Tue Aug 19 03:21:45 2014.
3 | You can adapt this file completely to your liking, but it should at least
4 | contain the root `toctree` directive.
5 |
6 | ================================================
7 | Python黑魔法手册
8 | ================================================
9 |
10 | Contents:
11 |
12 | .. toctree::
13 | :maxdepth: 2
14 | :glob:
15 |
16 | preface
17 | chapters/*
18 | aboutme
19 | roadmap
20 |
21 |
22 |
--------------------------------------------------------------------------------
/source/preface.rst:
--------------------------------------------------------------------------------
1 | ==================================
2 | 前言
3 | ==================================
4 |
5 | ----------------------------------
6 | 关于博客
7 | ----------------------------------
8 | 这个博客于2020年8月3日发布完成,使用的是 Sphinx 来生成文档,使用 Github 托管文档,并使用 Read the Doc 发布文档。
9 |
10 |
11 | ----------------------------------
12 | 作者的话
13 | ----------------------------------
14 |
15 | Python 是一门对编程新手非常友好的语言,通常花个两个月的时间,就能开始自己写代码,做项目。
16 |
17 | 但也因为过于高级,给予了开发者很高的自由度。这本身没有问题,但是想要写出优雅的 Python 代码,需要 Coder 有一定的代码审美能力,才能很好的驾驭。
18 |
19 | 这本电子教程,是我个人花了很多的时间,将自己这些年来写 Python 的一些心得整理所成。
20 |
21 | 内容包含各种你在教材上、培训视频中无法习得的冷门知识,魔法知识,以及开发技巧,不管对于新手还是老手,我想都会有一定的帮助。
22 |
23 | ----------------
24 |
25 |
--------------------------------------------------------------------------------
/source/roadmap.rst:
--------------------------------------------------------------------------------
1 | ===========
2 | Roadmap
3 | ===========
4 |
5 | 2020/08/03:
6 |
7 | ::
8 |
9 | | github项目搭建,readthedocs文档生成。
10 | | 整个项目的框架完成
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/source/robots.txt:
--------------------------------------------------------------------------------
1 | User-agent: *
2 | Sitemap: http://magic.iswbm.com/sitemap.xml
3 |
--------------------------------------------------------------------------------
/usercustomize.py:
--------------------------------------------------------------------------------
1 | msg=r"""
2 |
3 | _ooOoo_
4 | o8888888o __________________________________
5 | 88" . "88 | 爬虫工程师平安 后端工程师平安 |
6 | (| -_- |) | 数据分析师平安 自动化运维平安 |
7 | O\ = /O <__________________________________|
8 | ____/`---'\____
9 | . ' \\| |// `.
10 | / \\||| : |||// \
11 | / _||||| -:- |||||- \
12 | | | \\\ - /// | |
13 | | \_| ''\---/'' | |
14 | \ .-\__ `-` ___/-. /
15 | ___`. .' /--.--\ `. . __
16 | ."" '< `.___\_<|>_/___.' >'"".
17 | | | : `- \`.;`\ _ /`;.`/ - ` : | |
18 | \ \ `-. \_ __\ /__ _/ .-` / /
19 | ======`-.____`-.___\_____/___.-`____.-'======
20 | `=---='
21 |
22 | .............................................
23 | 佛祖保佑 永无BUG
24 | """
25 | print(msg)
26 |
--------------------------------------------------------------------------------