├── .gitignore ├── README.md └── content ├── Python_books.md ├── Python_skills.md ├── Python_standard_modules.md ├── Python_tips.md └── Python_tools.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | 5 | # C extensions 6 | *.so 7 | 8 | # Distribution / packaging 9 | .Python 10 | env/ 11 | build/ 12 | develop-eggs/ 13 | dist/ 14 | downloads/ 15 | eggs/ 16 | lib/ 17 | lib64/ 18 | parts/ 19 | sdist/ 20 | var/ 21 | *.egg-info/ 22 | .installed.cfg 23 | *.egg 24 | 25 | # PyInstaller 26 | # Usually these files are written by a python script from a template 27 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 28 | *.manifest 29 | *.spec 30 | 31 | # Installer logs 32 | pip-log.txt 33 | pip-delete-this-directory.txt 34 | 35 | # Unit test / coverage reports 36 | htmlcov/ 37 | .tox/ 38 | .coverage 39 | .cache 40 | nosetests.xml 41 | coverage.xml 42 | 43 | # Translations 44 | *.mo 45 | *.pot 46 | 47 | # Django stuff: 48 | *.log 49 | 50 | # Sphinx documentation 51 | docs/_build/ 52 | 53 | # PyBuilder 54 | target/ 55 | 56 | 57 | # Local settings 58 | local_settings.py 59 | 60 | # vim 61 | *.swp 62 | 63 | # pycharm 64 | .idea/ 65 | 66 | # mac 67 | .DS_Store 68 | 69 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Python Skills 2 | 3 | 本项目是我复习 Python 相关编程知识、资料、技巧过程中整理、总结的产物(未完待续,我会把它写完的!) 4 | 5 | - [收益匪浅的书籍](https://github.com/521xueweihan/Python_Skills/blob/master/content/Python_books.md) 6 | - [常用的技巧](https://github.com/521xueweihan/Python_Skills/blob/master/content/Python_skills.md) 7 | - [好用的标准库](https://github.com/521xueweihan/Python_Skills/blob/master/content/Python_standard_modules.md) 8 | - [有意思的 tips](https://github.com/521xueweihan/Python_Skills/blob/master/content/Python_tips.md) 9 | - [便利的工具](https://github.com/521xueweihan/Python_Skills/blob/master/content/Python_tools.md) 10 | -------------------------------------------------------------------------------- /content/Python_books.md: -------------------------------------------------------------------------------- 1 | # Python 书籍推荐 2 | 3 | # 介绍 4 | 以下书籍和资料全部为开源、免费。欢迎 Star 这些项目,给这些书的作者以支持。 5 | 6 | ## 初级 7 | - [廖雪峰 Python 教程](http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000) 8 | - [笨方法学 Python](https://github.com/521xueweihan/python) 9 | 10 | ## 进阶 11 | - [Python 进阶](https://eastlakeside.gitbooks.io/interpy-zh/content/) 12 | - [Python 之旅](https://github.com/ethan-funny/explore-python) 13 | - [Python CookBook](https://github.com/yidao620c/python3-cookbook) 14 | - [Stack Overflow 关于 Python 的部分](https://taizilongxu.gitbooks.io/stackoverflow-about-python/content/index.html) 15 | -------------------------------------------------------------------------------- /content/Python_skills.md: -------------------------------------------------------------------------------- 1 | # Python 的常用技巧 2 | 3 | ## 介绍 4 | Python 包含了很多语法特性,理解了这些编码的技巧,可以让 Python 使用起来更加得心应手。同时还会介绍了一些 Python 如何解决并发问题。 5 | 6 | ## 目录 7 | * [一、语法特性](#一语法特性) 8 | * [1. 魔法方法](#1-魔法方法) 9 | * [1.1 `__new__`](#11-`__new__`) 10 | * [1.2 `__getattribute__`](#12-`__getattribute__`) 11 | * [1.3 其它魔法方法](#13-其它魔法方法) 12 | * [2. 装饰器](#2-装饰器) 13 | * [2.1 装饰器执行顺序](#21-装饰器执行顺序) 14 | * [3. 上下文管理](#3-上下文管理) 15 | * [4. 可迭代对象、迭代器、生成器](#4-可迭代对象迭代器生成器) 16 | * [4.1 可迭代对象(Iterable)](#41-可迭代对象iterable) 17 | * [4.2 迭代器(Iterator)](#42-迭代器iterator) 18 | * [4.3 生成器(Generator)](#43-生成器generator) 19 | * [5. super](#5super) 20 | * [二、性能](#二性能) 21 | * [1. GIL](#1-gil) 22 | * [2. PyPy](#2-pypy) 23 | 24 | ## 一、语法特性 25 | ### 1. 魔法方法 26 | Python 的类是个很好玩的东西,它约定了很多‘特殊的方法’,例如:最常见的 `__init__` 方法,当实例化类的对象时,就会调用 `__init__` 方法;使用 `print` 该类的时候,会调用类的 `__str__` 方法,等等... 27 | 28 | 这些 Python 约定好的方法,就叫做‘魔法方法’。目的是:为了让实现定制类更加简单、用起来更加方便。比如:我要定制一个类的 `print` 输出内容,只需要实现 `__str__` 方法就可以了,在调用时也不需要 `print TestClass.__str__()`,直接 `print A()` 就可以了。 29 | 30 | #### 1.1 `__new__` 31 | `__new__` 方法总是和 `__init__` 方法放在一起讨论。 32 | - `__new__`:创建实例(先调用); 33 | - `__init__`:初始化实例(后调用); 34 | - `__new__` 是类方法,`__init__` 是实例方法; 35 | - 重载 `__new__` 方法,需要返回类的实例; 36 | 37 | `__new__` 最常见的使用场景是:实现单例模式 —— 不管实例化多少次,该类只有一个实例,代码如下: 38 | 39 | ```python 40 | class Singleton(object): 41 | _instance = None 42 | def __new__(cls, *args, **kw): 43 | if not cls._instance: 44 | cls._instance = super(Singleton, cls).__new__(cls, *args, **kw) 45 | return cls._instance # 必须要返回类的实例 46 | ``` 47 | 48 | #### 1.2 `__getattribute__` 49 | 不管访问的属性是否存在都会调用这个方法,访问属性,访问优先级别:`类属性 -> 实例属性 -> __getattr__` 50 | 51 | 在重载 `__getattribute__` 方法时,需要注意防止死循环。 52 | 53 | ```python 54 | class A(object): 55 | def __init__(self): 56 | self.name = 'A' 57 | 58 | def __getattribute__(self, item): 59 | return self.__dict__[item] # 调用 __dict__ 获取属性时是通过 __getattribute__,所以这么写是个死循环 60 | a = A() 61 | a.name # 报错:RuntimeError: maximum recursion depth exceeded 62 | 63 | #-----正确方式如下-----# 64 | 65 | class B(object): 66 | def __init__(self): 67 | self.name = 'B' 68 | 69 | def __getattribute__(self, item): 70 | return super(B, self).__getattribute__(item) 71 | b = B() 72 | b.name # 输出:B 73 | ``` 74 | 75 | #### 1.3 其它魔法方法 76 | - `__str__` 是用 print 和 str 显示的结果,`__repr__` 是直接显示的结果 77 | - `__getitem__` 用类似 `obj[key]` 的方式对对象进行取值 78 | - `__getattr__` 用于获取不存在的属性 `obj.attr` 79 | - `__call__` 使得可以对实例进行调用 80 | 81 | 参考: 82 | - [定制类和魔法方法](http://funhacks.net/explore-python/Class/magic_method.html) 83 | 84 | 85 | ### 2. 装饰器 86 | 在不改动原函数代码的前提下,通过装饰器实现给原函数扩展功能(进行‘装饰’)。 87 | 88 | 下面为装饰器的示例代码: 89 | ```python 90 | #!/usr/bin/env python 91 | # -*- coding:utf-8 -*- 92 | # 93 | # Author : XueWeiHan 94 | # Date : 17/5/5 上午10:32 95 | # Desc : 装饰器示例代码 96 | from functools import wraps 97 | 98 | def hello(fn): 99 | def wrap(): 100 | print 'hello' 101 | fn() 102 | return wrap 103 | 104 | 105 | @hello 106 | def simple_example(): 107 | print 'world' 108 | 109 | 110 | simple_example() 111 | 112 | 113 | def add1(fn): 114 | # 装饰器不带参数,被装饰的函数结果+1 115 | @wraps(fn) 116 | def wrap(*args): 117 | return fn(*args) + 1 118 | return wrap 119 | 120 | 121 | def addnum(add_num): 122 | # 装饰器带参数,被装饰的函数结果+add_num 123 | def real_decorator(fn): 124 | @wraps(fn) 125 | def wrap(*base_num): 126 | return fn(*base_num) + add_num 127 | return wrap 128 | return real_decorator 129 | 130 | 131 | @add1 132 | def value1(): 133 | return 1 134 | 135 | 136 | @add1 137 | def value2(base_num): 138 | return base_num 139 | 140 | 141 | @addnum(4) 142 | def value3(): 143 | return 1 144 | 145 | 146 | @addnum(10) 147 | def value4(base_num): 148 | return base_num 149 | 150 | print value1() 151 | print value1.__name__ 152 | 153 | print value2(2) 154 | print value2.__name__ 155 | 156 | print value3() 157 | print value3.__name__ 158 | 159 | print value4(4) 160 | print value4.__name__ 161 | 162 | ``` 163 | 164 | 参考: 165 | - [Python 修饰器的函数式编程](http://coolshell.cn/articles/11265.html) 166 | 167 | #### 2.1 装饰器执行顺序 168 | 装饰器等同于:`f = decorator_b(decorator_a(f))`,装饰顺序按靠近函数顺序执行,调用时由外而内,执行顺序和装饰顺序相反。 169 | 170 | ```python 171 | def decorator_a(func): 172 | print 'Get in decorator_a' 173 | def inner_a(*args, **kwargs): 174 | print 'Get in inner_a' 175 | return func(*args, **kwargs) 176 | return inner_a 177 | 178 | def decorator_b(func): 179 | print 'Get in decorator_b' 180 | def inner_b(*args, **kwargs): 181 | print 'Get in inner_b' 182 | return func(*args, **kwargs) 183 | return inner_b 184 | 185 | @decorator_b 186 | @decorator_a 187 | def f(x): 188 | print 'Get in f' 189 | return x * 2 190 | 191 | f(1) 192 | 193 | Get in decorator_a 194 | Get in decorator_b 195 | Get in inner_b 196 | Get in inner_a 197 | Get in f 198 | ``` 199 | 参考: 200 | - [Python 装饰器执行顺序迷思](https://segmentfault.com/a/1190000007837364) 201 | 202 | ### 3. 上下文管理 203 | 上下文管理是用于便于精确地分配和释放资源。例如:文件IO、数据库连接等。这些操作在使用完,都需要释放资源。 204 | 205 | 上下文管理是通过 Python 关键字 with 触发,在自定义类中实现 `__enter__` 和 `__exit__` 两个魔法方法。 206 | 1. 上下文开始时调用 `__enter__` 方法,如果该方法又返回值,该返回值会赋值给 `as` 后面的变量 207 | 2. 结束时调用 `__exit__` 方法,该方法还可以优雅的处理异常 208 | 209 | 下面为上下文管理的示例代码: 210 | ```python 211 | #!/usr/bin/env python 212 | # -*- coding:utf-8 -*- 213 | # 214 | # Author : XueWeiHan 215 | # Date : 17/5/7 下午4:50 216 | # Desc : 上下文管理示例代码 217 | 218 | 219 | class File(object): 220 | def __init__(self, path, method_type): 221 | self.fb = open(path, method_type) 222 | 223 | def __enter__(self): 224 | # 如果有 return 的对象,则会赋值给 as 后面的变量 225 | return self.fb 226 | 227 | def __exit__(self, exc_type, exc_val, exc_tb): 228 | """ 229 | :param exc_type: 异常类型 230 | :param exc_val: 异常信息 231 | :param exc_tb: 异常错误 traceback 232 | :return: 如果 return True 则不会抛出异常 233 | """ 234 | self.fb.close() 235 | if exc_val: 236 | return False 237 | else: 238 | return True 239 | 240 | 241 | with File('./find_pi.py', 'r+') as fb: 242 | print fb.read() # 正确调用 243 | # print fb.rrr() # 没有这个方法,引出异常 244 | ``` 245 | 246 | 也可以使用 `contextlib` 模块提供的 `contextmanager` 装饰器实现上下文管理 247 | 248 | ### 4. 可迭代对象、迭代器、生成器 249 | #### 4.1 可迭代对象(Iterable) 250 | Python 中任意的对象,只要它定义了可以返回一个迭代器的 `__iter__` 方法,或者定义了可以支持下标索引的 `__getitem__` 方法,那么它就是一个可迭代对象。可以用在 `for` 语句中的都是可迭代的,比如:list、string、dict、set 251 | 252 | 这些可迭代的对象你可以随意的读取所以非常方便易用,但是**你必须把它们的值放到内存里,当它们有很多值时就会消耗太多的内存。** 253 | 254 | #### 4.2 迭代器(Iterator) 255 | 任意对象,只要定义了 `next` 方法和 `__iter__` 方法返回自己本身,它就是一个迭代器。 256 | 257 | 像 list、set 等,是没有 `next` 方法,所以不是迭代器。但是,可以使用 `iter` 内置方法实现迭代器。 258 | 259 | 使用类实现迭代器,示例代码如下: 260 | ```python 261 | class Squares(object): 262 | def __init__(self, start, stop): 263 | self.start = start 264 | self.stop = stop 265 | def __iter__(self): 266 | return self 267 | def next(self): 268 | if self.start >= self.stop: 269 | raise StopIteration 270 | current = self.start * self.start 271 | self.start += 1 272 | return current 273 | ``` 274 | 275 | #### 4.3 生成器(Generator) 276 | 通过 `yield` 关键字,实现:不需要在生成元素巨多的迭代器时([1, 2, ..., 100000000]),就开辟所有空间。而是每次调用 `next` 方法或 `for` 循环到该元素时才计算该位置元素的数值(即:惰性计算)。 277 | 278 | ```python 279 | #!/usr/bin/env python 280 | # -*- coding:utf-8 -*- 281 | # 282 | # Author : XueWeiHan 283 | # Date : 17/5/9 上午12:28 284 | # Desc : 生成器示例代码 285 | 286 | # 报错,因为太大了,生成不了 287 | # big_list1 = range(1111111111111111111) 288 | 289 | 290 | def generate_big_list(n): 291 | """ 292 | 使用生成器,生成大数据集 293 | """ 294 | start = 0 295 | while start < n: 296 | yield start 297 | start += 1 298 | 299 | big_list2 = generate_big_list(1111111111111111111) 300 | 301 | for fi_big_list2 in big_list2: 302 | print fi_big_list2 303 | 304 | # 使用内置 xrange 生成大数据集, 305 | big_list3 = xrange(1111111111111111111) 306 | 307 | # for fi_big_list3 in big_list3: 308 | # print fi_big_list3 309 | 310 | ``` 311 | 312 | 参考: 313 | - [Python 进阶——生成器篇](https://eastlakeside.gitbooks.io/interpy-zh/content/Generators/) 314 | - [Python 关键字 yield 的解释](http://pyzh.readthedocs.io/en/latest/the-python-yield-keyword-explained.html) 315 | 316 | ### 5. super 317 | Python 继承中,重写(在不改变方法名的前提下修改方法)父类方法实例代码(不推荐): 318 | ```python 319 | class Base(object): 320 | def __init__(self): 321 | print "enter Base" 322 | print "leave Base" 323 | 324 | class A(Base): 325 | def __init__(self): 326 | print 'enter A' 327 | Base.__init__(self) 328 | print 'leave A' 329 | 330 | a = A() 331 | # 输出结果: 332 | # enter A 333 | # enter Base 334 | # leave Base 335 | # leave A 336 | ``` 337 | 338 | Python 重写父类方法时,**推荐使用 `super` 关键字**。 339 | 340 | - 语法:`super(子类名, self/cls).需要继承的父类方法(参数)` 341 | - 好处: 342 | - 父类名称改变,不需要修改子类中继承的地方 343 | - 多继承时,继承顺序按照子类的 `mro` 方法返回的列表中的顺序访问 344 | 345 | 多继承实例代码如下: 346 | ```python 347 | class Base(object): 348 | def __init__(self): 349 | print "enter Base" 350 | print "leave Base" 351 | 352 | class A(Base): 353 | def __init__(self): 354 | print "enter A" 355 | super(A, self).__init__() 356 | print "leave A" 357 | 358 | class B(Base): 359 | def __init__(self): 360 | print "enter B" 361 | super(B, self).__init__() 362 | print "leave B" 363 | 364 | class C(A, B): 365 | def __init__(self): 366 | print "enter C" 367 | super(C, self).__init__() 368 | print "leave C" 369 | 370 | print C.mro() 371 | # 输出:[__main__.C, __main__.A, __main__.B, __main__.Base, object] 372 | 373 | c = C() 374 | # 输出如下: 375 | # enter C 376 | # enter A 377 | # enter B 378 | # enter Base 379 | # leave Base 380 | # leave B 381 | # leave A 382 | # leave C 383 | 384 | ``` 385 | 386 | 参考: 387 | - [你不知道的 super](http://funhacks.net/explore-python/Class/super.html) 388 | 389 | ## 二、性能 390 | 关于性能问题,可以归结于两种类型:计算密集型、I/O密集型。 391 | 392 | - 计算密集型是计算量大,所以需要**并行**计算。 393 | - I/O 密集型问题在于数据读取的等待时间,同时发起 I/O 就很重要(后面就是谁先处理完I/O就搞它),所以**并发**才是解决的关键。 394 | 395 | 这就很通畅了,针对性能问题的不同场景,就要对症下药。什么多线程、多进程、协程、事件循环等技术都是为了解决上述两类问题的方案,所以先清楚性能的“痛处”是哪里,后面再介绍每种技术(解决方案、解药)的时候,才能有更深的体会。 396 | 397 | ### 1. GIL 398 | 再聊到 Python 性能问题时,必然提到 GIL 全局解释器锁,一个货真价实的**全局线程锁**,它存在于主流解释器 CPython 中(有的解释器就没有GIL)。 399 | 400 | #### 1.1 GIL 的作用 401 | 解释型语言比如 Python 是需要先通过解释器,把 Python 代码解释成字节码(bytecode)。而 GIL 的作用就是保证字节码层是线程安全的,这里需要弄明白的是字节码和 Python 代码的层级不同。GIL 保证字节码的线程安全,并不能保证 Python 代码的线程安全。因为一行 Python 代码,对应的字节码并不是一行: 402 | ```Python 403 | >>> def f(): 404 | ... global num 405 | ... num += 1 406 | ... 407 | >>> dis.dis(f) 408 | 3 0 LOAD_GLOBAL 0 (num) 409 | 3 LOAD_CONST 1 (1) 410 | 6 INPLACE_ADD 411 | 7 STORE_GLOBAL 0 (num) 412 | 10 LOAD_CONST 0 (None) 413 | 13 RETURN_VALUE 414 | ``` 415 | 这个例子中,实现`num + = 1`需要 4个字节码,又因为线程可能在 `LOAD_GLOBAL` 和 `STORE_GLOBAL` 之间切换,所以导致多线程执行 `f()` 时会出现脏数据。 416 | 417 | **GIL 的作用小结:** 418 | - GIL 保证同一时间只有一个线程在执行字节码 419 | 420 | 参考: 421 | - [Why does Python provide locking mechanisms if it's subject to a GIL?](https://stackoverflow.com/questions/26873512/why-does-python-provide-locking-mechanisms-if-its-subject-to-a-gil) 422 | 423 | #### 1.2 GIL 对线程切换的影响 424 | Python 的线程虽然是系统级别原生线程,但是由于有 GIL 的存在,每次线程切换之前都需要先获取 GIL,之后才能进行线程调度。遇到 I/O 情况,将释放GIL。非 I/O 情况下线程在执行特定步数(ticks)后释放GIL。 425 | 426 | - 使得线程切换**代价更高**。 427 | - 无法实现真正的线程并行 428 | 429 | 所以: 430 | 1. 计算密集型场景:**单核单线程** > **单核多线程** > **多核多线程**(多核线程切换:CPU2 上的线程被唤醒时,CPU1 上的线程又把 GIL 锁上了,所以中间造成了很多浪费。同时,更多的线程检查GIL情况也造成了资源浪费。) 431 | 2. I/O密集型场景:多线程 > 单线程 432 | 433 | 434 | 参考: 435 | - [Understanding the Python GIL](http://www.dabeaz.com/GIL/) 436 | - [python 线程,GIL 和 ctypes](http://zhuoqiang.me/python-thread-gil-and-ctypes.html) 437 | 438 | #### 1.3 总结 439 | 1. 计算密集型采用**多进程**(multiprocessing库)、C 扩展 440 | 2. I/O密集型采用**多线程**(threading库)、事件循环 441 | 442 | 443 | ### 2. PyPy 444 | PyPy 是 Python 的一种解释器,用 Python 的子集 rPython 实现的。 445 | 446 | PyPy 的执行效率高于 CPython 是因为 JIT,也就是解释完 Python 代码后,编译代码的过程中会有优化,实现效率的提升。但是由于 JIT 的优化过程是耗时的,所以的编译过程比 CPython 漫长。 447 | 448 | 参考: 449 | - [PyPy 为什么会比 CPython 还要快?](https://www.zhihu.com/question/19588346) 450 | 451 | ### 3. 多进程 452 | multiprocessing 库,根据 CPU 数量(cpu_count)创建进程池,每个核上一个进程减少切换进程的损耗,性能最高。 453 | 454 | ```python 455 | from multiprocessing import Pool 456 | import time 457 | 458 | def f(x): 459 | return x*x 460 | 461 | if __name__ == '__main__': 462 | pool = Pool(processes=4) # start 4 worker processes 463 | 464 | result = pool.apply_async(f, (10,)) # evaluate "f(10)" asynchronously in a single process 465 | print result.get(timeout=1) # get 是阻塞操作 prints "100" unless your computer is *very* slow 466 | 467 | print pool.map(f, range(10)) # prints "[0, 1, 4,..., 81]" 468 | 469 | it = pool.imap(f, range(10)) 470 | print it.next() # prints "0" 471 | print it.next() # prints "1" 472 | print it.next(timeout=1) # prints "4" unless your computer is *very* slow 473 | 474 | result = pool.apply_async(time.sleep, (10,)) 475 | print result.get(timeout=1) # raises multiprocessing.TimeoutError 476 | ``` 477 | 478 | 参考: 479 | - [multiprocessing](https://docs.python.org/2/library/multiprocessing.html) 480 | 481 | ### 4. 多线程 482 | threading 库 483 | 484 | 多线程的使用存在**线程安全问题**,即:有可能出现多个线程同时更改数据造成所得到的数据是脏数据(错误的数据)。所以,在多线程执行写入的操作时,要考虑线程同步问题。也就是需要加锁或使用队列,以保证同一时间只有一个线程写入数据。(注意:加锁操作完后,要释放) 485 | 486 | ```python 487 | >>> from threading import Thread 488 | >>> class Worker(Thread): 489 | ... def __init__(self, id): 490 | ... super(Worker, self).__init__() 491 | ... self._id = id 492 | ... def run(self): 493 | ... print "I am worker %d" % self._id 494 | ... 495 | >>> t1 = Worker(1) 496 | >>> t2 = Worker(2) 497 | >>> t1.start(); t2.start() 498 | I am worker 1 499 | I am worker 2 500 | 501 | # using function could be more flexible 502 | >>> def Worker(worker_id): 503 | ... print "I am worker %d" % worker_id 504 | ... 505 | >>> from threading import Thread 506 | >>> t1 = Thread(target=Worker, args=(1,)) 507 | >>> t2 = Thread(target=Worker, args=(2,)) 508 | >>> t1.start() 509 | I am worker 1 510 | I am worker 2 511 | ``` 512 | 513 | 514 | ### 5. 协程 515 | 1. 协程是比线程**更轻量**(资源使用更少)。 516 | 517 | 2. 不同于线程,线程是抢占式的调度,而协程是协同式的调度,协程需要**自己做调度**。 518 | 519 | 3. 协程是**线程安全的**,一个进程可以同时存在多个协程,但是只有一个协程是激活的。 520 | 521 | 522 | ### 6. 事件循环(Event Loop) 523 | ### 7. gentlet 524 | ### 8. Gevent 525 | -------------------------------------------------------------------------------- /content/Python_standard_modules.md: -------------------------------------------------------------------------------- 1 | # Python 好用的标准库 2 | 3 | ## 介绍 4 | Python 自带了很多库,称为:标准库。 5 | 6 | 下面介绍了我在学习、使用、工作、查阅资料过程中收集的,好用的 Python 标准库。 7 | 8 | ## itertools 9 | ## collections 10 | 11 | ## timeit 12 | 显示代码片段的运行时间。timeit它接受一个参数为每个测试中调用被计时语句的次数,默认为**一百万次**;返回所耗费的**秒数**。 13 | 14 | 1.通过命令运行 15 | 16 | ```sh 17 | python -m timeit '"-".join([str(n) for n in range(100)])' 18 | 19 | 结果: 20 | 10000 loops, best of 3: 27.5 usec per loop 21 | ``` 22 | 23 | 2.代码内调用 24 | 25 | ```python 26 | import timeit 27 | print timeit.timeit('"-".join(str(n) for n in range(100))', number=10000) 28 | 29 | 结果: 30 | 0.3018611848820001 31 | ``` 32 | 33 | 3.输出执行某个函数所用时间 34 | 35 | ```python 36 | def test(): 37 | """Stupid test function""" 38 | L = [i for i in range(100)] 39 | 40 | if __name__ == '__main__': 41 | import timeit 42 | print(timeit.timeit("test()", setup="from __main__ import test")) 43 | ``` 44 | [官方文档 timeit](https://docs.python.org/2.7/library/timeit.html) 45 | 46 | ## bisect 47 | 通过二分算法,维持一个有序列表,每增加一个元素,列表无需重新排序。因为,二分法找到增加的元素在列表中的位置,然后直接插入。而不是把增加的元素放到列表中,再重新进行一次排序。对于很长的列表,会节省很多时间和空间。 48 | ```python 49 | import timeit 50 | import bisect 51 | import random 52 | 53 | 54 | def test_bisect(l): 55 | for i in range(0, 10): 56 | r = random.randint(1, 100000) 57 | bisect.insort(l, r) 58 | 59 | 60 | def normal(l): 61 | for i in range(0, 10): 62 | r = random.randint(1, 100000) 63 | l.append(r) 64 | l.sort() 65 | 66 | if __name__ == '__main__': 67 | print(timeit.timeit('test_bisect([num for num in xrange(100000000)])', setup='from __main__ import test_bisect', number=1)) 68 | print(timeit.timeit('normal([num for num in xrange(100000000)])', setup='from __main__ import normal', number=1)) 69 | 70 | 结果: 71 | 8.9976670742 72 | 23.4078929424 73 | ``` 74 | [官方文档 bisect](https://docs.python.org/2.7/library/bisect.html) 75 | 76 | ## cProfile 77 | 这个库是2.5新加的,比profile性能好,推荐使用。cProfile可以用于分析python脚本的运行时间和脚本中耗时的代码。 78 | 79 | ```python 80 | import cProfile 81 | cProfile.run('a = range(1000000) print a') 82 | 83 | # 输出: 84 | """cProfile.run('range(1000000)') 85 | 3 function calls in 0.030 seconds 86 | 87 | Ordered by: standard name 88 | 89 | ncalls tottime percall cumtime percall filename:lineno(function) 90 | 1 0.006 0.006 0.030 0.030 :1() 91 | 1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 92 | 1 0.024 0.024 0.024 0.024 {range} 93 | """ 94 | #ncalls 函数的被调用次数 95 | #tottime 函数总计运行时间,除去函数中调用的函数运行时间 96 | #percall 函数运行一次的平均时间,等于tottime/ncalls 97 | #cumtime 函数总计运行时间,含调用的函数运行时间 98 | #percall 函数运行一次的平均时间,等于cumtime/ncalls 99 | #filename:lineno(function) 函数所在的文件名,函数的行号,函数名 100 | 101 | ``` 102 | [官方文档 cProfile](https://docs.python.org/2/library/profile.html) 103 | 104 | ## operator 105 | 相当于一个工具箱,你可以通过`operator.xx()`调用该对象的拥有的各种方法,还是用代码说明吧: 106 | 107 | ```python 108 | import operator 109 | # 先来个简单的 110 | a = operator.add(3, 4) 111 | print a # 7 112 | 113 | # 如果有一个类,你要得到他的所有属性 114 | class Test(object): 115 | def __init__(self): 116 | self.name = 'xueweihan' 117 | self.age = 23 118 | self.sex = 'boy' 119 | t = Test() 120 | f = operator.attrgetter('name', 'age', 'sex') 121 | all_attr = f(t) 122 | print all_attr # 需要获取的属性的元祖 ('xueweihan', 23, 'boy') 123 | 124 | # 实用场景,排序,提取值 125 | inventory = [('apple', 3), ('banana', 2), ('pear', 5), ('orange', 1)] 126 | getcount = itemgetter(1) 127 | map(getcount, inventory) #[3, 2, 5, 1] 128 | 129 | sorted(inventory, key=getcount) # [('orange', 1), ('banana', 2), ('apple', 3), ('pear', 5)] 130 | 131 | ``` 132 | [官方文档 operator](https://docs.python.org/2/library/operator.html) 133 | 134 | ## pprint 135 | 顾名思义:“漂亮地打印”。适用场景,需要 `print` 特别长的字典。例如: 136 | 137 | ```python 138 | # 例如直接print一个结果,`quote_result`是一个很长的字典 139 | print quote_result 140 | # 打印结果如下 141 | { u'is_done': True, u'detail': {..省略...}, u'require_owner_info': False} 142 | 143 | # 调用pprint的pprint()函数,打印结果 144 | import pprint 145 | pprint.pprint(quote_result) 146 | # 打印结果如下 147 | {u'detail': {u'biz_info': {u'No': u'', 148 | u'discount': u'0.5670', 149 | u'discount1': u'0.5670', 150 | u'insure_type': 1, 151 | u'payList': [], 152 | u'premium_detail': {u'combust': {u'amount': u'27385.60', 153 | u'code': u'combust', 154 | u'group_code': 2, 155 | u'premium': u'77.64'}, 156 | ... 157 | u'third': {u'amount': u'300000.00', 158 | u'code': u'third', 159 | u'group_code': 1, 160 | u'premium': u'695.14'}}, 161 | u'standard': u'3278.25', 162 | u'startDate': u'2016-04-14', 163 | u'total': u'1858.77'}, 164 | u'is_support_counter': True, 165 | u'pay_info': [{u'total': u'1858.77', u'total_cent': 185877}], 166 | u'require_owner_info': False, 167 | }, 168 | u'is_done': True, 169 | u'is_success': True, 170 | } 171 | 172 | ``` 173 | 174 | [官方文档 pprint](https://docs.python.org/2.7/library/pprint.html) 175 | -------------------------------------------------------------------------------- /content/Python_tips.md: -------------------------------------------------------------------------------- 1 | # Python Tips 2 | 3 | ## 介绍 4 | Python 自带了很多好用的工具和有意思的小技巧,这些‘小’而实用的技巧,可以使用一行代码或者一条命令,带来很多便利。 5 | 6 | # 小技巧 7 | Python 代码中的便利的代码片段。 8 | 9 | ## Mac 下发送通知 10 | ```python 11 | import os 12 | 13 | def notify(title, text): 14 | # 调用 mac osascript 命令 15 | os.system(""" 16 | osascript -e 'display notification "{}" with title "{}"' 17 | """.format(text, title)) 18 | 19 | notify("通知", "三年二班xxx,到教导处来一趟。") 20 | ``` 21 | 22 | ## print 输出到文件中 23 | ``` 24 | print >> file("myfile", "w"), "hello world" 25 | ``` 26 | 27 | ## 变量值交换 28 | ``` 29 | a = 1 30 | b = 2 31 | a, b = b, a # a=2, b=1 32 | ``` 33 | 34 | 35 | # 小工具 36 | Python 自带电池(battery included),直接通过命令行使用。 37 | 38 | ## json 格式化工具 39 | ``` 40 | echo '{"foo": "lorem", "bar": "ipsum"}' | python -m json.tool 41 | curl https://randomuser.me/api/ | python -m json.tool 42 | ``` 43 | 44 | ## 本地启动 server(可用于文件下载) 45 | ``` 46 | python -m SimpleHTTPServer 8000 47 | ``` 48 | 会直接在机器上起一个 FTP 服务,内容为当前目录下的内容。 49 | 50 | ## 使用默认浏览器打开url 51 | ``` 52 | python -m webbrowser 53 | 参数: 54 | -n open new window 55 | -t open new tab 56 | url target url 57 | ``` 58 | -------------------------------------------------------------------------------- /content/Python_tools.md: -------------------------------------------------------------------------------- 1 | # Python Tools 2 | 3 | ## 开发 4 | 下面列举了我在 Python 开发过程中用到的工具。 5 | 6 | 1. pip:python 包管理,[入门教程](http://www.cnblogs.com/xueweihan/p/4981704.html) 7 | 8 | 2. virtualenvwrapper:python虚拟环境管理,[入门教程](http://www.cnblogs.com/xueweihan/p/5531197.html) 9 | 10 | 3. ipython:交互式python解释器,带有自动补全等高级功能。安装:`sudo pip install ipython` 11 | 12 | 4. unittest、coverage:第一个用于单元测试,第二个用于检测代码的测试覆盖率。 13 | 14 | 5. Anaconda:用于安装科学包、数据分析包很好用。缺点是大,它附带了 conda、Python 和多个科学包及其依赖项,应用程序 conda 是包和环境管理器。[官网](https://www.anaconda.com/) 15 | 16 | 17 | ## Web 18 | 1. httpie:通过命令行测试web服务,[使用方法](https://httpie.org/doc#examples) 19 | 20 | 2. Postman:一个很强大的 API 调试、HTTP 请求工具,[下载](https://www.getpostman.com/) 21 | 22 | 3. wrk:一个很简单的 http 性能测试工具,以多路复用的方式达到高并发,从而进行压力测试。[地址](https://github.com/wg/wrk) 23 | --------------------------------------------------------------------------------