第1页
+
论 Python 与设计模式
赖勇浩(http://laiyonghao.com)
2013-‐12-‐8
珠海
第2页
+
设 计模式?
第3页
+
自 我介绍
n
赖勇浩
n
从业 8 年多,主要编程语言是
Python
n
game
-‐>
webgame
-‐>
web
n
常在珠三角技术沙龙出没
n
http://laiyonghao.com
3
第4页
+
P yCon
的老朋友
4
第5页
+
好,正式开始吧!
5
第6页
+
先 热热场子……
n
写 Python
代码赚钱的,有没有?
6
第7页
+
先 热热场子……
n
写 Python
代码赚钱的,有没有?
n
写 Python 超过 1 年的,有没有?
7
第8页
+
再 热热场子……
n
读过《设计模式——可复用面向对 象软件的基础》这本书的有没有?
8
第9页
+
再 热热场子……
n
读过《设计模式——可复用面向对 象软件的基础》这本书的有没有?
n
读过《Head
First 设计模式》 的有没有?
9
第10页
10
一个观点
第11页
+
我也希望是这样……
但事实是……
11
第12页
+
先 看事实:工厂函数(方法)
int(…)
float(…)
type(name,
bases,
dict)
>>>
class
X(object):
...
a
=
1
...
>>>
X
=
type('X',
(object,),
dict(a=1))
collections.namedtuple()
datatime.fromtimestamp(…)
Decimal.from_float(…)
Fraction.from_float(…)
Fraction.from_decimal(…)
第13页
+
先 看事实:享元(FlyWeight)
>>>
i
=
10
>>>
j
=
5
+
5
>>>
id(i)
140479275503872
>>>
id(j)
140479275503872
>>>
a
=
'ab'
>>>
b
=
'a'
+
'b'
>>>
id(a)
==
id(b)
True
13
第14页
+
先 看事实:享元(FlyWeight)
14
>>>
i
=
10
>>>
j
=
5
+
5
>>>
id(i)
140479275503872
>>>
id(j)
140479275503872
>>>
a
=
'ab'
>>>
b
=
'a'
+
'b'
>>>
id(a)
==
id(b)
True
>>>
a
=
a
*
10
>>>
intern(a)
'abababababababababab'
>>>
b
=
'abababababababababab’
>>>
c
=
'abababababababababa'
+
'b’
>>>
d
=
'ab'
*
10
>>>
id(a)
==
id(b)
==
id(c)
==
id(d)
True
第15页
+
先 看事实:适配器
15
import
SocketServer
class
ThreadedTCPServer(SocketServer.ThreadingMixIn,
SocketServer.TCPServer):
pass
第16页
+
先 看事实:代理模式
16
>>>
import
weakref
>>>
class
A(object):pass
...
>>>
a
=
A()
>>>
a.attr
=
1
>>>
a.attr
1
>>>
a1
=
weakref.proxy(a)
>>>
a1.attr
1
>>>
a1
<weakproxy
at
0x10dc375d0
to
A
at
0x10dc3a410>
第17页
+
先 看事实:模板方法
17
import
SocketServer
class
MyTCPHandler(SocketServer.BaseRequestHandler):
def
handle(self):
self.data
=
self.request.recv(1024).strip()
print
"{}
wrote:".format(self.client_address[0])
print
self.data
self.request.sendall(self.data.upper())
第18页
+
先 看事实:模板方法
From
abc
import
ABCMeta
class
C:
__metaclass__
=
ABCMeta
@abstractmethod
def
my_abstract_method(self,
...):
...
18
第19页
+
所 以,真相是……
n
标准库都在用……
n
标准库都推荐用……
n
怎么可以说不需要?!
19
第20页
20
+
所
以我们不是不需要模式……
而是要 Pythonic 的模式实现……
第21页
+
不 Pythonic 的设计模式:单例
21
class
Singleton(object):
def
__new__(cls,
*args,
**kw):
if
not
hasattr(cls,
'_instance'):
orig
=
super(Singleton,
cls)
cls._instance
=
orig.__new__(cls,
*args,
**kw)
return
cls._instance
第22页
+
单 例的三个需求:
n
只能有一个实例;
n
它必须自行创建这个实例;
n
它必须自行向整个系统提供这个
实例。
22
第23页
+
单 例遇上并行
class
Singleton(object):
objs
=
{}
objs_locker
=
threading.Lock()
def
__new__(cls,
*args,
**kv):
if
cls
in
cls.objs:
return
cls.objs[cls]
23
第24页
+
单 例遇上并行
cls.objs_locker.acquire()
try:
if
cls
in
cls.objs:
return
cls.objs[cls]
cls.objs[cls]
=
object.__new__(cls)
finally:
cls.objs_locker.release()
24
第25页
+
P ythonic
的设计模式:单例
25
n
重新审视 Python 的语法元素,尽量利用已有基础设施。
n
模块
n
所有的变量都会绑定到模块; n
模块只初始化一次;
n
import
机制是线程安全的(保证了在并发状态下模块也只有一个实
例);
n
惯用法:
n
文件名首字母大写,如 Moon.py
n
__all__
第26页
+
不 Pythonic 的设计模式:装饰器
26
第27页
+
代 码大概是这样的
class
darkroast(Beverage):
def
cost(self):return
0.99
…
class
Whip(Beverage):
def
__init__(self,
beverage):
self._beverage
=
beverage
def
cost(self):
return
self._beverage.cost()
+
0.1
print
Whip(Mocha(darkroast())).cost()
27
第28页
+
P ythonic 的设计模式:装饰器
def
beverage(cost):
def
_(orig
=
0.0):
return
orig
+
cost
return
_
darkroast
=
beverage(0.99)
whip
=
beverage(0.1)
mocha
=
beverage(0.2)
print
whip(mocha(darkroast()))
28
第29页
+
其 它设计模式:Borg(MonoState)
29
n
保持对象的唯一性并不重要,只 要共享状态就行
n
Alex
Martelli
n
http:// code.activestate.com/ recipes/66531/
第30页
+
其 它设计模式:Borg(MonoState)
30
class
Borg(object):
_state
=
{}
def
__new__(cls,
*args,
**kw):
ob
=
super(Borg,
cls).__new__(cls,
*args,
**kw)
ob.__dict__
=
cls._state
return
ob
第31页
+
动 态语言特有的设计模式:mixin
31
n
动态地改变实例的类型的基类,在不修改生成实例过程的情况下, 给实例增加(改变)功能。可用以实现插件框架。
class
Bird(object):pass
bird
=
Bird()
class
FlyMixin:
def
fly(self):print
'I
can
fly.'
bird.__class__.__bases__
+=
(FlyMixin,
)
bird.fly()
第32页
+
动 态语言特有的模式:duck
typing 32
n
一个对象有效的语义,不是由继承自特定的类或实现特定的接口, 而是由当前方法和属性的集合决定。
n
当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子, 那么这只鸟就可以被称为鸭子。(James
Whitcomb
Riley)
n
干掉模板方法?
n
不,模板方法是想要保证子类实现接口
第33页
+
利 用设计模式提供更好的接口
33
n
getopt
n
optparse
n
argparse
n
docopt
n
Command-‐line
interface
description
language
n
define
interface
for
your
command-‐line
app,
and
n
automatically
generate
parser
for
it.
n
解释器模式
第34页
+
d ocopt
34
第35页
+
解 释器模式的应用
n
GM 指令
player
0
money
10000
player
0
attack
10000
monster
0
die
scene
monsters
die
n
过场剧情脚本
monster
0
spawn
0,0
monster
0
moveto
0,-‐10
monster
0
attack
monster
0
moveto
0,0
35
第36页
+
Q&A
mail@laiyonghao.com
36