python 学习笔记html
PYTHON-进阶-魔术方法小结(方法运算符重载)
python有着像C++类似的运算符重载,只须要在类中重写__add__、sub 等方法,就能够直接对对象进行 + - 等操做,就好像内置对象同样。也能够重写__getattr__、__setattr__等方法来操做属性,init、del、str 、__len__等基本方法均可以重载,比较符的重载包括cmp、lt、__gt__等,以及getitem、__setitem__等操做索引的方法。总之,彻底能够经过重载将一个类写的python之父都不认得。python
传统咱们实现消费者 生产者模型 都是须要经过多线程之间 互相协做,一个线程生产,一个线程消费。协程就是将多线程的事情在一个线程里面干了。传统咱们一个函数老是一个入口,一个出口,很明确。协程就是容许一个子程序内部能够中断,而后执行其余子程序,在适当的时候再返回来继续执行,即便在while True这样的函数。这样的话咱们就能够生产 后就调用消费者,而后消费后再继续生产。
python 2.x中实现协程的方式 是经过generator,yield 中止一个子程序后,能够经过send(xxx) 继续执行
协程的好处:sql
极高的效率,不须要操做系统切换线程,只是程序内部控制segmentfault
由于协程是一个线程执行,那怎么利用多核CPU呢?最简单的方法是多进程+协程,既充分利用多核,又充分发挥协程的高效率,可得到极高的性能。数组
经过协程也能够将一个复杂的程序分红多个相互协做的子程序,就好像unix 的管道同样,read ---> grep ---> print 这样,程序会更简单明了,复用性更高多线程
# 简洁高效的生产消费模式 # 装饰器, 用来自动启动协程 def coroutine(func): def go(*args, **kwargs): g = func(*args, **kwargs) g.send(None) return g return go @coroutine def consumer(): r = '' while True: n = yield r if not n: return print ('consume {}'.format(n)) time.sleep(1) r = '200 OK' def producer(target): while True: n = random.randint(1, 100) print ('produce {}'.format(n)) r = target.send(n) print ('consumer return {}'.format(r)) if __name__ == '__main__': producer(consumer())
generator 跟普通的方法差很少,只是能够经过yield返回多个值,以下闭包
def gen(): yield 1 yield 2 g = gen() print g # 输出<generator object gen at 0x00000000026BCFC0> print g.next() # 输出1 print g.next() # 输出2 print g.next() # StopIteration 异常
经过dir(g) 能够看到generator 实现了__iter__ 和 next 方法,因此generator 也是一个迭代器, 生成器能够用来简化迭代器的实现app
# 简化版的小写字母生成器,相对自定义迭代器来讲,真的简单多了 def lower_letters(): current = 'a' while current <= 'z': yield current current = chr(ord(current) + 1) for letter in lower_letters(): print letter
python 中的for in语法,能够遍历iterable 对象,例如list,array,map等,其实就是用iter()构造了一个iterator,并捕获StopIteration异常dom
_iter = iter(iterableObj) while True: try: x = _iter.next() except StopIteration: break do_your_func(x)
iterator 和 iterable 本质上的区别是 iterator 实现了__next__(python2.x 是next)和 __iter__方法,而iterable只实现了__iter__方法,经过dir([1,2]) 能够看到数组中只实现了iter ,只是iterable对象函数
因此,咱们能够自定义一个迭代器,只要实现了__next__ 和 iter,而且__next__ 抛出StopIteration异常
class UpperLetter(object): def __init__(self): self.current = 'A' def next(self): if self.current > 'Z': raise StopIteration() result = self.current self.current = chr(ord(self.current) + 1) return result def __iter__(self): return self letters = UpperLetter() # 自定义的迭代器能够经过for in遍历哦 for letter in letters: print (letter)
约定这是python中的特殊方法,一般你将覆盖这些方法,实现所需的功能,例如__init__
约定这是私有方法,外部不能访问。
对于解释器来讲, from <模块 包名> import * 是没法导入以_开头的方法
python都对象之间赋值都是拷贝引用,若是要拷贝对象,须要使用copy模块
userInfo = { "resultCode": 0, "users": { 'name': "jobs" } } a = userInfo b = copy.copy(userInfo) c = copy.deepcopy(userInfo) # 修改原来的对象 userInfo['resultCode'] = 1 userInfo['users']['name'] = 'ryan' print a print b print c # 输出: # {'resultCode': 1, 'users': {'name': 'ryan'}} # {'resultCode': 0, 'users': {'name': 'ryan'}} # {'resultCode': 0, 'users': {'name': 'jobs'}}
能够看到,传引用的全改了,浅拷贝的话子对象仍是保留着原来的引用,因此子对象跟着改了,深拷贝岿然不动!
切片是python一个颇有趣的语法糖,提供了简洁的方法来取一个数组的一部分
L=[1, 2, 3,4,5] print L[1: 3] # 取索引1到索引3,不包含索引3 print L[:] # 第一个参数不填表示第一位,最后一个参数不填表示取最后一位 print L[-2:] # 负数表示倒数第n个元素 print L[::2] # 最后一个参数表示隔几个取一次,跟range相似 # 输出 # [2, 3] # [1, 2, 3, 4, 5] # [4, 5] # [1, 3, 5] # 优雅地将数组 进行分组操做,这里若是i + 3大于数组len, 切片也能自动切到最后一截哈哈 for i in range(0, len(L), 3): print L[i: i+3] # 输出 # [1, 2, 3] # [4, 5]
父函数中返回的函数引用了父函数中的参数或者局部变量,这个函数就称为闭包。所以,闭包也是携带状态的函数,而且它的状态能够对外隐藏起来。闭包之于父函数就好像实例之于类
通常来讲闭包不能修改外部变量,由于对于同名变量的修改 python 把它看作了 子函数中的 局部变量,因此你直接修改会返回UnboundLocalError: local variable 'm' referenced before assignment错误(听说在python3中能够用nolocal 声明外部变量便可修改)
闭包函数相对于普通函数多出了一个__closure__属性,这是一个元组,这个元祖里面包含了全部闭包函数中引用到的外部变量
参考:
说说 Python 中的闭包
装饰器就是一种特殊的闭包,经过传递一个待修饰的函数 给 修饰函数,并返回一个修饰后的函数,能够用@decoratorFunc 来简化语法,装饰器的做用就是为已经存在的函数或对象添加额外的功能
参考:
Python 的闭包和装饰器:https://segmentfault.com/a/1190000004461404
详解 Python 的装饰器
[ x * x for x in list] & { x[a] : x[b] for x in list}
var = 1 def func1(): # 此处声明 global var 解决 var = var + 1 return var print func1() # 报错UnboundLocalError: local variable 'var' referenced before assignment # 由于咱们企图在内层改变外层的var,因此python就把他当作局部变量了,那很明显,这个var在局部并无赋值
用with as 字句代替以前的try .... finally fs.close()之类的语句方便了不少
tuple 就是不可变的list, 用(1, 2, 3)定义
**若是要定义只有一个元素的tuple,不能定义为(1),python把他当作数字1(括号运算),正确的写法为(1, )
python 的默认参数若是为数组的话,要千万当心了
def func2(array=[]): array.append("haha") print array func2() # 输出 ['haha'] func2() # 输出 ['haha', 'haha']
为何每次调用的结果都不同? 由于默认参数的值在函数定义的时候就生成好了,因此当默认参数指向的是 可变对象如list
就会改变它的值,因此**默认参数必定要是不可变对象"",如str,int等
要往可变参数中传入一个数组,有两种方法
def func3(*arr): for i in arr: print i nums = [1, 2, 3] func3(nums[0], nums[1], nums[2]) # 不得不说,这种写法巨丑 func3(*nums) # 好看
可变参数在方法中就是一个tuple,而关键字参数在方法中就是一个dict,它能够扩展函数的功能,让用户自定义配置,例如sqlalchemy的create_engine(*args, kwargs)就使咱们能够根据须要定义encoding,echo等参数
一样的,要传入一个dict给可变参数的方法能够用**dict**
星解提供了一个很艺术化的方法来unpack一个list或dict
def test(x, y, z): print(x, y, z) testDict = {'x': 1, 'y': 2, 'z': 3} testList = [10, 20, 30] test(*testDict) test(*testList) #1-> x y z #2-> 10 20 30