class: middle, inverse, center ``` _ _ _ __ _ _| |_| |__ ___ _ __ | '_ \| | | | __| '_ \ / _ \| '_ \ | |_) | |_| | |_| | | | (_) | | | | | .__/ \__, |\__|_| |_|\___/|_| |_| |_| |___/ . ``` # 编程进阶 ### [LiNing](http://www.lining0806.com/) #### 2017.05 --- class: inverse ## 一句话搞定一件事 ![Python](img/code.png) --- class: middle, inverse, center ## Python 2 or Python 3 ? ## 后续讲解基于 Python 2.7 ... --- class: inverse ## Python编码 ### 转码思路 #### 字符串在Python内部的表示是unicode编码,在编码转换时通常需要以unicode作为中间编码。 #### 先将其他编码的字符串解码(decode)成unicode,再从unicode编码(encode)成另一种编码。 ### 转码举例 #### s.decode('utf-8', 'ignore').encode('gbk', 'ignore') #### 先由utf-8转为unicode,再由unicode转为gbk,ignore表示忽略非法字符 ``` s = u'中文' # s为unicode print isinstance(s, unicode) # True print s.encode('utf-8', 'ignore') # 中文 # 由unicode转为utf-8,ignore表示忽略非法字符 ``` --- class: inverse ## 异常处理 ### try-except-finall结构 ``` import traceback try: xxx except Exception, e: print e print traceback.format_exc() raise finally: print 'end' ``` ### 记录错误 ``` import logging except StandardError, e: logging.exception(e) ``` --- class: inverse ## 字符串 ### 不可变类型 ``` >>> a = 'abc' >>> a 'abc' >>> b = a.replace('a', 'A') >>> a 'abc' >>> b 'Abc' ``` ### 带关键字与不带关键字的格式化 ``` >>> 'Hello %(name)s !' % {'name': 'James'} 'Hello James !' >>> 'Hello %s !' % 'James' 'Hello James !' >>> 'Hello {name} !'.format(name='James') 'Hello James !' >>> 'Hello {} !'.format('James') 'Hello James !' ``` --- class: inverse ## 列表 ### 列表是由一系列元素组成的有序的序列。 ### append与extend ``` list1.append(xxx) # 表示在list1后添加元素xxx list1.extend(list2) # 表示在list1后添加序列list2 ``` ### zip函数 ``` >>> list1 = ['a', 'b'] >>> list2 = ['1', '2'] >>> zip(list1, list2) [('a', '1'), ('b', '2')] >>> zip(*[list1, list2]) [('a', '1'), ('b', '2')] ``` --- class: inverse ## 列表 ### enumerate函数:把list变成'索引-元素'对 ``` >>> word = ['c', 'b', 'd', 'a'] >>> word.sort() >>> word ['a', 'b', 'c', 'd'] >>> for i, value in enumerate(word): print i, value 0 a 1 b 2 c 3 d ``` ### enumerate函数实现 ``` def enumerate(sequence, start=0): n = start for elem in sequence: yield n, elem n += 1 ``` --- class: inverse ## 列表 ### 列表去重 ``` >>> l = [1, 2, 4, 7, 2, 1, 8, 6, 1] >>> list(set(l)) # 不保证顺序 [1, 2, 4, 6, 7, 8] >>> sorted(list(set(l)), reverse=True) # 顺序 [8, 7, 6, 4, 2, 1] >>> {}.fromkeys(l).keys() # 不保证顺序 [1, 2, 4, 6, 7, 8] >>> from collections import OrderedDict >>> OrderedDict().fromkeys(l).keys() # 按照原有序列顺序 [1, 2, 4, 7, 8, 6] ``` ### 列表推导式 ``` >>> [x*x for x in range(10)] # 一层循环 [0, 1, 4, 9, 16, 25, 36, 49, 64, 81] >>> [m + n for m in 'ABC' for n in 'XYZ'] # 两层循环 ['AX', 'AY', 'AZ', 'BX', 'BY', 'BZ', 'CX', 'CY', 'CZ'] ``` --- class: inverse ## 列表 ### 引用、浅复制、深复制 ``` >>> import copy >>> l = [0, [1, 2], 3] >>> l1 = l # 引用 >>> l2 = l[:] # 浅复制 >>> l3 = copy.copy(l) # 浅复制 >>> l4 = copy.deepcopy(l) # 深复制 >>> l [0, [1, 2], 3] >>> l1, l2, l3, l4 ([0, [1, 2], 3], [0, [1, 2], 3], [0, [1, 2], 3], [0, [1, 2], 3]) >>> l[0] = 9 >>> l [9, [1, 2], 3] >>> l1, l2, l3, l4 ([9, [1, 2], 3], [0, [1, 2], 3], [0, [1, 2], 3], [0, [1, 2], 3]) >>> l[1][1] = 9 >>> l [9, [1, 9], 3] >>> l1, l2, l3, l4 ([9, [1, 9], 3], [0, [1, 9], 3], [0, [1, 9], 3], [0, [1, 2], 3]) ``` --- class: inverse ## 列表 ### is 与 == #### is 比较两个对象的标识(引用) #### == 比较两个对象的值(内容) ``` >>> a = [1, 2, 3] >>> b = a >>> b is a True >>> b == a True >>> b = a[:] >>> b is a False >>> b == a True ``` --- class: inverse ## 列表 ``` def fib1(max_num): L = [] n, a, b = 0, 0, 1 while n < max_num: L.append(b) a, b = b, a + b n += 1 return L ``` ### 迭代器 iterator #### \_\_iter\_\_()方法:返回迭代器对象本身。 #### next()方法:返回迭代器的下一个对象。 ### 生成器 generator #### g = (x*x for x in range(5)) # generator #### yield --- class: inverse ## 列表 ### 迭代器实现Fibonacci数列 ``` class fib2(object): def __init__(self, max_num): self.max_num = max_num self.n, self.a, self.b = 0, 0, 1 def __iter__(self): return self def next(self): if self.n < self.max_num: r = self.b self.a, self.b = self.b, self.a + self.b self.n += 1 return r raise StopIteration() ``` --- class: inverse ## 列表 ### 生成器实现Fibonacci数列 ``` def fib3(max_num): n, a, b = 0, 0, 1 while n < max_num: yield b a, b = b, a + b n += 1 >>> g_gen = fib3(10) >>> g_gen
>>> for i in g_gen: print i 1 1 2 3 5 8 13 21 34 55 ``` --- class: inverse ## 列表 ### 协程 coroutine #### 生成器是数据的生产者,协程则是数据的消费者。 ``` def my_coroutine(a=None): print 'coroutine start...' while True: f = (yield a) print 'result: {}'.format(f) >>> c = my_coroutine() >>> next(c) coroutine start... >>> c.send('first') result: first >>> c.send('second') result: second >>> c.close() ``` --- class: inverse ## 元组 ### 元组是只读的列表,不能对其修改。 ### 定义一个只有1个元素的tuple: #### 建议 ``` t = ('xxx',) ``` #### 不建议,为什么? ``` t = ('xxx') ``` --- class: inverse ## 字典 ### 字典是由键key和值value的对应组合成的无序的序列。 ### 字典构造 ``` >>> dict([('a', '1'), ('b', '2')]) {'a': '1', 'b': '2'} >>> dict.fromkeys(['a', 'b'], 1) {'a': 1, 'b': 1} >>> dict.fromkeys('ab', 1) {'a': 1, 'b': 1} >>> {'a':'1', 'b':'2'} {'a': '1', 'b': '2'} >>> dict(zip(['a', 'b'], ['1', '2'])) {'a': '1', 'b': '2'} >>> dict([('a', '1'), ('b', '2')]) {'a': '1', 'b': '2'} >>> dict(a='1', b='2') {'a': '1', 'b': '2'} >>> dict(a=1, b=2) {'a': 1, 'b': 2} ``` --- class: inverse ## 字典 ### 判断一个字典是否有某个key ``` key in Dict Dict.has_key(key) ``` ### 获得指定key的值 ``` Dict.get(key, default) # 如果没有key,返回default值,在Dict中不添加该键值。 Dict.setdefault(key, default) # 如果没有key,返回default值,并且在Dict中添加该键值。 Dict[key] # 如果没有key,返回error。 ``` --- class: inverse ## 字典 ### items(), keys(), values() ``` >>> Dict = {'a':1, 'b':2, 'c':3, 'd':4} >>> Dict.items() [('a', 1), ('c', 3), ('b', 2), ('d', 4)] >>> Dict.keys() ['a', 'c', 'b', 'd'] >>> Dict.values() [1, 3, 2, 4] >>> Dict.iteritems()
>>> for k, v in Dict.iteritems(): print k, v a 1 c 3 b 2 d 4 >>> Dict.iterkeys()
>>> Dict.itervalues()
``` --- class: inverse ## 字典 ``` >>> dct = dict() >>> dct['foo'] Traceback (most recent call last): File "
", line 1, in
dct['foo'] KeyError: 'foo' ``` ### 特殊方法 \_\_missing\_\_ ``` class Dict(dict): def __missing__(self, key): ## 当查找不到key的时候,会执行该方法 self[key] = [] return self[key] >>> dct = Dict() >>> dct['foo'] [] ``` --- class: inverse ## 字典 ### 按照values值进行降序排列 ``` >>> x = {'a': 2, 'b': 4, 'c': 3, 'd': 1, 'e': 0} >>> x.items() [('a', 2), ('c', 3), ('b', 4), ('e', 0), ('d', 1)] ``` #### 方法1 ``` >>> sorted_x = sorted(x.items(), key=lambda xx:xx[1], reverse=True) >>> sorted_x [('b', 4), ('c', 3), ('a', 2), ('d', 1), ('e', 0)] ``` #### 方法2 ``` >>> sorted_x = x.items() >>> sorted_x.sort(key=lambda xx:xx[1], reverse=True) >>> sorted_x [('b', 4), ('c', 3), ('a', 2), ('d', 1), ('e', 0)] ``` --- class: inverse ## 字典 ### 合并字典 ``` def merge(ds): r = {} for d in ds: for k in d: if k in r: r[k] += d.get(k) else: r[k] = d.get(k) return r >>> d1 = {'a':1, 'b':2, 'c':3} >>> d2 = {'b':4, 'd':5, 'e':6} >>> d3 = {'b':3, 'c':1, 'e':1} >>> d = merge([d1, d2, d3]) >>> d {'a': 1, 'c': 4, 'b': 9, 'e': 7, 'd': 5} ``` --- class: inverse ## 集合 ### 集合与字典类似,也是一组key的集合,但不存储value。 ### 集合构造 ``` >>> set(['a', 'b', 'c']) set(['a', 'c', 'b']) >>> set('abc') set(['a', 'c', 'b']) >>> {'a', 'b', 'c'} set(['a', 'c', 'b']) ``` ### 交集、并集、差集、对称差集 ``` x.intersection(y) 或 x&y x.union(y) 或 x|y x.difference(y) 或 x-y x.symmetric_difference(y) 或 x^y ``` --- class: inverse ## 类与对象 ### 普通继承 ``` class Bird(object): def __init__(self): self.hungry = True def eat(self): if self.hungry: print 'Aaaah...' self.hungry = False else: print 'No, thanks!' class SongBird(Bird): def sing(self): pass >>> s = SongBird() >>> s.sing() >>> s.eat() Aaaah... >>> s.eat() No, thanks! ``` --- class: inverse ## 类与对象 ### super继承 ``` class SongBird(Bird): def __init__(self): self.sound = 'Squawk!' def sing(self): print self.sound >>> s = SongBird() >>> s.sing() Squawk! >>> s.eat() Traceback (most recent call last): File "
", line 1, in
s.eat() File "
", line 5, in eat if self.hungry: AttributeError: 'SongBird' object has no attribute 'hungry' ``` --- class: inverse ## 类与对象 ### super继承 ``` class SongBird(Bird): def __init__(self): # Bird.__init__(self) super(SongBird, self).__init__() self.sound = 'Squawk!' def sing(self): print self.sound >>> s = SongBird() >>> s.sing() Squawk! >>> s.eat() Aaaah... >>> s.eat() No, thanks! ``` --- class: inverse ## 类与对象 ### 直接调用内部属性 ``` class Student(object): def __init__(self, name, score): self.name = name self.score = score >>> s = Student('Bart', 59) >>> s.score 59 >>> s.score = 60 >>> '%s: %s' % (s.name, s.score) 'Bart: 60' ``` --- class: inverse ## 类与对象 ### 通过类成员访问内部属性 ``` class Student(object): def __init__(self, name, score): self._name = name self._score = score def get_score(self): return self._score def set_score(self, value): self._score = value def print_score(self): print '%s: %s' % (self._name, self._score) >>> s = Student('Bart', 59) >>> s.get_score() 59 >>> s.set_score(60) >>> s.print_score() Bart: 60 ``` --- class: inverse ## 类与对象 ### @property与property() ``` class Student(object): def __init__(self, name, score): self._name = name self._score = score @property def score(self): return self._score @score.setter def score(self, value): self._score = value @score.deleter def score(self): del self._score >>> s = Student('Bart', 59) >>> s.score 59 >>> s.score = 60 >>> s.score 60 >>> del s.score ``` --- class: inverse ## 类与对象 ### @property与property() ``` class Student(object): def __init__(self, name, score): self._name = name self._score = score def get_score(self): return self._score def set_score(self, value): self._score = value def del_score(self): del self._score score = property(get_score, set_score, del_score) >>> s = Student('Bart', 59) >>> s.score 59 >>> s.score = 60 >>> s.score 60 >>> del s.score ``` --- class: inverse ## 类与对象 ### 动态绑定 ``` from types import MethodType class Student(object): pass def set_age(self, age): self.age = age def set_score(self, score): self.score = score >>> s = Student() >>> s.name = 'Michael' >>> s.name 'Michael' >>> s.set_age = MethodType(set_age, s, Student) >>> s.set_age(25) >>> s.age 25 >>> Student.set_score = MethodType(set_score, None, Student) >>> s.set_score(100) >>> s.score 100 ``` --- class: inverse ## 类与对象 ### 限制变量 \_\_slots\_\_ ``` from types import MethodType class Student(object): __slots__ = ('name', 'age', 'set_age') >>> s = Student() >>> s.name = 'Michael' >>> s.name 'Michael' >>> s.set_age = MethodType(set_age, s, Student) >>> s.set_age(25) >>> s.age 25 >>> Student.set_score = MethodType(set_score, None, Student) >>> s.set_score(100) Traceback (most recent call last): File "
", line 1, in
s.set_score(100) File "
", line 2, in set_score self.score = score AttributeError: 'Student' object has no attribute 'score' ``` --- class: inverse ## 类与对象 ### type 动态创建类 ``` def __init__(cls, func): cls.func = func def hello(cls): print 'hello world' Hello = type('Hello', (object,), {'__init__':__init__, 'hello':hello}) >>> h = Hello(lambda a, b: a+b) >>> h.hello() hello world >>> type(Hello)
>>> type(h)
``` --- class: inverse ## 类与对象 ### 元类 \_\_metaclass\_\_ 动态创建类 ``` class HelloMeta(type): def __new__(cls, name, bases, dct): def __init__(cls, func): cls.func = func def hello(cls): print 'hello world' # t = type.__new__(cls, name, bases, dct) t = super(HelloMeta, cls).__new__(cls, name, bases, dct) t.__init__ = __init__ t.hello = hello return t class New_Hello(object): __metaclass__ = HelloMeta >>> h = New_Hello(lambda a, b: a+b) >>> h.hello() hello world >>> type(New_Hello)
>>> type(h)
``` --- class: inverse ## 魔法方法 Magic Method ### 会话管理器 #### __enter__:定义当使用with语句定义一个代码块时会话管理器应该做什么。 #### __exit__:定义当一个代码块被执行或者终止后会话管理器应该做什么。 ``` class FileObject(object): def __init__(self, filepath='sample.txt'): self.file = open(filepath, 'r+') def __enter__(self): # 与with语句对应 return self.file def __exit__(self, exc_type, exc_val, exc_tb): self.file.close() del self.file with FileObject() as fp: print fp.read() ``` --- class: inverse ## 魔法方法 Magic Method ### 对象的魔法方法 #### __getattr__:查询不在__dict__系统中的对象属性或者对象方法。 ``` class A(object): def __getattr__(self, attr): def _(*args, **kw): print args, kw return _ pass >>> a = A() >>> a.xxx
>>> a.xxx1(1, 2, key='ssss') (1, 2) {'key': 'ssss'} >>> a.xxx2(1, 2) (1, 2) {} >>> a.xxx3(1, 2, 3) (1, 2, 3) {} ``` --- class: inverse ## 魔法方法 Magic Method ### 魔法方法举例 ``` class Student(object): def __init__(self, name): self.name = name def __str__(self): return 'Student object (name: %s)' % self.name def __call__(self): print 'Student object (name: %s)' % self.name def __getattr__(self, attr): if attr == 'score': return 99 else: def func(*args, **kw): return args, kw return func ``` --- class: inverse ## 魔法方法 Magic Method ### 魔法方法举例 ``` >>> print(s) # 调用__str__方法 Student object (name: Michael) >>> s() # 调用__call__方法 Student object (name: Michael) >>> s.name # 调用存在的属性name 'Michael' >>> s.score # 调用不存在的属性score 99 >>> s.score1 # 调用不存在的属性score1
>>> s.function(1, 2, 3) # 调用不存在的方法function ((1, 2, 3), {}) ``` --- class: inverse ## 函数的参数传递 ### 参数定义 #### 在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去。 ``` def func(a, b, c=0, *args, **kw): print 'a =', a, 'b =', b, 'c =', c, \ 'args =', args, 'kw =', kw >>> func(1, 2) a = 1 b = 2 c = 0 args = () kw = {} >>> func(1, 2, c=3) a = 1 b = 2 c = 3 args = () kw = {} >>> func(1, 2, 3, 'a', 'b') a = 1 b = 2 c = 3 args = ('a', 'b') kw = {} >>> func(1, 2, 3, 'a', 'b', x=99) a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99} >>> args = (1, 2, 3, 4) >>> kw = {'x': 99} >>> func(*args, **kw) a = 1 b = 2 c = 3 args = (4,) kw = {'x': 99} ``` --- class: inverse ## 函数的参数传递 ### 默认参数 #### 默认参数必须为不可变对象,如None,string,tuple,不可为list类型。 ``` def add_end(L=[]): L.append('END') return L >>> add_end() ['END'] >>> add_end() ['END', 'END'] >>> add_end() ['END', 'END', 'END'] ``` 改为 ``` def add_end(L=None): if L is None: L = [] L.append('END') return L ``` --- class: inverse ## 函数的参数传递 ### 可变参数 #### 任意函数都可以表示成func(\*args, \*\*kw)形式。 ``` def func(a, b, c): print a, b, c >>> l = [1, 2, 3] >>> d = {'a':1, 'b':2, 'c':3} >>> func(*l) 1 2 3 >>> func(**d) 1 2 3 ``` --- class: inverse ## 函数式编程 ### lambda函数 #### 可以动态生成一个函数对象,但该函数只能有一个表达式。 ``` f = lambda x: x*x def f(x): return x*x ``` ### map(), reduce(), filter() ``` >>> range(0,10) [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] >>> map(lambda x:x*2, range(0,10)) [0, 2, 4, 6, 8, 10, 12, 14, 16, 18] >>> reduce(lambda x,y:x*10+y, range(0,10)) 123456789 >>> filter(lambda x:x%2==0, range(0,10)) [0, 2, 4, 6, 8] ``` --- class: inverse ## 函数式编程 ### 偏函数 partial #### 不需要定义新的函数,把函数的某些参数固定,返回一个新的函数。 ### 实现sequence的加法和乘法 ``` >>> from functools import partial >>> import operator >>> l = [i for i in range(1, 10)] >>> l [1, 2, 3, 4, 5, 6, 7, 8, 9] >>> sum = partial(reduce, operator.add) >>> sum(l) 45 >>> product = partial(reduce, operator.mul) >>> product(l) 362880 ``` --- class: inverse ## 函数式编程 ### 闭包 closure #### 指延伸了作用域的函数,它能访问定义体之外定义的环境变量,这个函数和它的环境变量合在一起,就构成了一个闭包。 ``` def lazy_sum(*args): def sum(x=0): # sum函数和变量args构成闭包 ax = x for n in args: # 闭包变量args是只读的,不能修改 ax = ax + n return ax return sum >>> f = lazy_sum(1, 3, 5, 7, 9) >>> >>> f
>>> f() 25 >>> f(1) 26 ``` --- class: inverse ## 装饰器 decorator ### 不修改函数的定义,在代码运行期间动态增加功能的方式。 ### 函数装饰器 ``` def decorator(func): def wrapper(*args, **kw): print 'input:', args, kw return func(*args, **kw) return wrapper @decorator def square_sum(*args, **kw): sum = 0 for i in args: sum += i**2 for j in kw.values(): sum += j**2 return sum >>> square_sum(3, 4, key=5) input: (3, 4) {'key': 5} 50 ``` --- class: inverse ## 装饰器 decorator ### 类装饰器 ``` class decorator(object): def __init__(self, func): self.func = func def __call__(self, *args, **kw): print 'input:', args, kw return self.func(*args, **kw) @decorator def square_sum(*args, **kw): sum = 0 for i in args: sum += i**2 for j in kw.values(): sum += j**2 return sum >>> square_sum(3, 4, key=5) input: (3, 4) {'key': 5} 50 ``` --- class: inverse ## 装饰器 decorator ### 带参数的装饰器 ``` def decorator(*args, **kw): text = args def _(func): def wrapper(*args, **kw): print 'text: %s' % text print 'input:', args, kw return func(*args, **kw) return wrapper return _ ``` #### 注意:decorator中的(\*args, \*\*kw) vs wrapper中的(\*args, \*\*kw) --- class: center, middle, inverse # Q & A --- class: center, middle, inverse ## 联系方式 ### Website: [宁哥的小站](http://www.lining0806.com) ### GitHub: [lining0806](http://github.com/lining0806) ### Gmail: [lining0806@gmail.com](mailto:lining0806@gmail.com) --- class: center, middle, inverse # 谢谢大家 #### Made in [Remark](http://remarkjs.com)