In code we trust. –BitCoin
numpy.rollaxis 的另类理解方式
rollaxis 实例
in[1]:
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np
import scipy.misc
in[2]:
b = scipy.misc.imread('magic.png')
in[3]:
b.dtype
out[3]:
dtype('uint8')
in[4]:
toimage(b)
out[4]:
in[5]:
b.shape
out[5]:
(810, 572, 4)
in[6]: 该操作与 c = np.swapaxes(b, 0, 1)
等效
c = np.rollasix(b, 1)
in[7]:
c.shape
out[7]:
(572, 810, 4)
in[8]:
toimage(c)
out[9]:
python常用设计模式
行文结构参照以下项目。 项目地址: https://github.com/faif/python-patterns
《松本行弘的程序世界》对三人组的《设计模式》称赞有加:
把普通人难以学习和吸收的内隐知识变成形式只是的功绩是无与伦比的。
在设计模式原书中一共提到23种常用的设计模式,分为三大类:生成模式(creational), 构造模式(structural), 行为模式(behavioral)。该项目同样按照这三大类进行了分类整理, 同时还补充了一些python常用的其他场景的特用模式。 在整理这片文章的过程中,我忽略了一些无聊的模式,并引用或者另写了一些更好的代码用例。
————————生成模式—————————
abstract_factory / 抽象工厂
最直白的就是“鸡鸭鹅狗猫都是动物”:
1 |
|
borg / 集体主义模式
emmm… https://blog.youxu.info/2010/04/29/borg/ 介绍了borg的出处。 borg就是python的singleton,但是与singleton不同的是,borg模式为多个对象共享单一状态, 而不是单一对象多个引用。
1 |
|
builder / 建造者模式
适用于构造复杂对象, 将构造过程拆分为独立模块
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
# copy from《Mastering Python Design Patterns》
class Computer:
def __init__(self, serial_number):
self.serial = serial_number
self.memory = None
self.cpu = None
self.disk = None
def __str__(self):
return 'memory: {0} GB, cpu: {1}, disk: {2} GB'.format(
self.memory, self.cpu, self.disk
)
class ComputerBuilder:
def __init__(self):
self.computer = Computer('SN-12345555')
def configure_memory(self, memory):
self.computer.memory = memory
def configure_cpu(self, cpu):
self.computer.cpu = cpu
def configure_disk(self, disk):
self.computer.disk = disk
class HardwareEngineer:
def __init__(self):
self.builder = None
def construct_computer(self, memory, cpu, disk):
self.builder = ComputerBuilder()
self.builder.configure_memory(memory)
self.builder.configure_cpu(cpu)
self.builder.configure_disk(disk)
@property
def computer(self):
return self.builder.computer
engineer = HardwareEngineer()
engineer.construct_computer(16, 8, 500)
computer = engineer.computer
print(computer)
# memory: 16 GB, cpu: 8, disk: 500 GB
factory / 工厂模式
抽象工厂和工厂模式在python实现中的区别大概只是有没有继承关系了。。。
同样的,工厂方法也是用来实现通用接口。比如说下面这种多国语言翻译的例子。
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
class GreekGetter(object):
"""A simple localizer a la gettext"""
def __init__(self):
self.trans = dict(dog="σκύλος", cat="γάτα")
def get(self, msgid):
"""We'll punt if we don't have a translation"""
return self.trans.get(msgid, str(msgid))
class EnglishGetter(object):
"""Simply echoes the msg ids"""
def get(self, msgid):
return str(msgid)
def get_localizer(language="English"):
"""The factory method"""
languages = dict(English=EnglishGetter, Greek=GreekGetter)
return languages[language]()
if __name__ == '__main__':
# Create our localizers
e, g = get_localizer(language="English"), get_localizer(language="Greek")
# Localize some text
for msgid in "dog parrot cat bear".split():
print(e.get(msgid), g.get(msgid))
### OUTPUT ###
# dog σκύλος
# parrot parrot
# cat γάτα
# bear bear
lazy_evaluation / 惰性求值
Delays the eval of an expr until its value is needed and avoids repeated evals.
表达式计算延迟到调用时,同时避免重复计算
1
2
3
4
5
6
7
8
9
10
11
12
13
import functools
class cached_property(object):
def __init__(self, function):
self.function = function
functools.update_wrapper(self, function)
def __get__(self, obj, type_):
if obj is None:
return self
val = self.function(obj)
obj.__dict__[self.function.__name__] = val
return val
The cached_property(a.k.a lazy_property) is a decorator which convert a func into a lazy evaluation property. The first time property accessed, the func is called to get result and then the value is used the next time you access the property.
eg:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class LogHandler:
def __init__(self, file_path):
self.file_path = file_path
@cached_property
def load_log_file(self):
with open(self.file_path) as f:
# the file is to big that I have to cost 2s to read all file
return f.read()
log_handler = LogHandler('./sys.log')
# only the first time call will cost 2s.
print(log_handler.load_log_file)
# return value is cached to the log_handler obj.
print(log_handler.load_log_file)
pool /池模式
预初始化一批对象并保持可用状态。 pool模式常用来提供各种服务连接,比如各大数据库提供的ConnectionPool, python内建的 threadingPools。
1 |
|
protopype / 原型
通过clone原型来创建新的实例。似乎并没有人用过。。。
1
2
3
4
5
6
7
8
9
10
class Prototype(object):
value = 'default'
def clone(self, **attrs):
"""Clone a prototype and update inner attributes dictionary"""
# Python in Practice, Mark Summerfield
obj = self.__class__()
obj.__dict__.update(attrs)
return obj
————————生成模式—————————
adapter / 适配器
我想起了10年前家里用的万能充:万能充总是能通过改变自己的接口形状来适应不同的手机电池。
1 |
|
bridge / 桥接模式
桥接的使用集中在频繁更换实现方法时。用于把容易拆分的实现抽象成接口。然后挑选使用。
1 |
|
composite / 组合模式
一种表达树形结构的方法,恕在下才疏学浅,还没有注意到生产代码中的类似用例。
贴一段 soucemaking上的用例:
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
import abc
class Component(metaclass=abc.ABCMeta):
"""
Declare the interface for objects in the composition.
Implement default behavior for the interface common to all classes,
as appropriate.
Declare an interface for accessing and managing its child
components.
Define an interface for accessing a component's parent in the
recursive structure, and implement it if that's appropriate
(optional).
"""
@abc.abstractmethod
def operation(self):
pass
class Composite(Component):
"""
Define behavior for components having children.
Store child components.
Implement child-related operations in the Component interface.
"""
def __init__(self):
self._children = set()
def operation(self):
for child in self._children:
child.operation()
def add(self, component):
self._children.add(component)
def remove(self, component):
self._children.discard(component)
class Leaf(Component):
"""
Represent leaf objects in the composition. A leaf has no children.
Define behavior for primitive objects in the composition.
"""
def operation(self):
pass
def main():
leaf = Leaf()
composite = Composite()
composite.add(leaf)
composite.operation()
if __name__ == "__main__":
main()
faced / 门面
可以叫它总闸模式: 一个独立的模块单独负责所有子对象的运行。
举个极其抽象的例子:
1
2
3
4
5
6
7
def runner():
a = lambda: "task a"
b = lambda: "task b"
c = lambda: "task c"
tasks = [a, b, c]
task_ret = [task() for task in tasks]
print(task_ret)
flyweight / 享元
通过与其他相似的对象共享数据来达到节省内存的目的。
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
# -*- coding: utf-8 -*-
"""
*References:
http://codesnipers.com/?q=python-flyweights
http://yloiseau.net/articles/DesignPatterns/flyweight/
*TL;DR80
Minimizes memory usage by sharing data with other similar objects.
"""
import weakref
class FlyweightMeta(type):
def __new__(mcs, name, parents, dct):
"""
Set up object pool
:param name: class name
:param parents: class parents
:param dct: dict: includes class attributes, class methods,
static methods, etc
:return: new class
"""
dct['pool'] = weakref.WeakValueDictionary()
# 调用 type 的 new 方法。
return super(FlyweightMeta, mcs).__new__(mcs, name, parents, dct)
@staticmethod
def _serialize_params(cls, *args, **kwargs):
"""
Serialize input parameters to a key.
Simple implementation is just to serialize it as a string
"""
args_list = list(map(str, args))
args_list.extend([str(kwargs), cls.__name__])
key = ''.join(args_list)
return key
def __call__(cls, *args, **kwargs):
key = FlyweightMeta._serialize_params(cls, *args, **kwargs)
pool = getattr(cls, 'pool', {})
instance = pool.get(key)
if instance is None:
instance = super(FlyweightMeta, cls).__call__(*args, **kwargs)
pool[key] = instance
return instance
def with_metaclass(meta, *bases):
""" Provide python cross-version metaclass compatibility. """
return meta("NewBase", bases, {})
class Card2(with_metaclass(FlyweightMeta)):
def __init__(self, *args, **kwargs):
pass
if __name__ == '__main__':
# comment __new__ and uncomment __init__ to see the difference
# Tests with metaclass
instances_pool = getattr(Card2, 'pool')
cm1 = Card2('10', 'h', a=1)
cm2 = Card2('10', 'h', a=1)
cm3 = Card2('10', 'h', a=2)
print(f'id:{id(cm1)}, {cm1}')
print(f'id:{id(cm2)}, {cm2}')
print(f'id:{id(cm3)}, {cm3}')
assert (cm1 == cm2) != cm3
assert (cm1 is cm2) is not cm3
assert len(instances_pool) == 2
del cm1
assert len(instances_pool) == 2
del cm2
assert len(instances_pool) == 1
del cm3
assert len(instances_pool) == 0
front controtllor / 前端控制器
front controtollr 提供了一个中控平台控制和管理请求。
1
# 点击右上角查看示例
mvc&n-tier / 分层
mvc 和 n-tier 的差别就是, n-tier 模式中各模块为线性关系,而 mvc结构中,view 向controllor 发送更新信息,controllor更新model,然后view层获取model层的更新。
在应用中,我们通常用mvc,mvvc等来形容app的代码层级结构,而在基础设施搭建中,我们通常用n-tier来 描述该协议/模式的运行模式。比如网络的7层/3层结构。
mvc
1
# 点击右上角查看示例
3-tier
1
# 点击右上角查看示例
proxy / 代理
代理的核心思想是控制对一个对象的访问过程,比如网络代理,控制了网络访问的过程。
1 |
|
———————–行为模式—————————
chain / 责任链
责任链将多个对象连成一条链,并且沿着这条链传递请求,直到有对象处理为止。 该模式解耦了请求和处理者 ,客户端只要发送请求到责任链,无需关心请求的处理细节。
1 |
|
command / 命令模式
一种数据驱动的设计模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以 处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
1 |
|
iterator / 迭代器
emmm… class里的 magic methods __next__
, __iter__
, 函数中的yield
, 都可以用来
生成iterator。
一个简单的迭代器。
def aiter():
a = [1 ,2, 3, 4, 4, 5, 5, 6, 6, 7]
for i in a:
yield i
mediator / 中介
用来降低多个对象和类之间的通信复杂性。这种模式提供了一个中介类,该类通常处理不同类之间的通信, 并支持松耦合,使代码易于维护。 –> 想聊天的人多了,才出现了qq群。
1 |
|
memento / 备忘录
如果有了后悔药你写的代码该多放浪形骸?
1 |
|
observer / 观察者
常用的状态机订阅模式。
1 |
|
pub_sub / 发布 - 订阅
去年毕业的时候面试过一次今日头条, 当时就问了设计模式的发布 订阅模型。。可惜可惜除了那道题别的我连听都没听说过啊。。。。
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
"""
pattern publish subscribe
~~~~~~~~~~~~~~~~~~~~~~~~~
"""
class Provider:
def __init__(self):
self.msg_queue = []
self.subscribers = {}
def notify(self, msg):
self.msg_queue.append(msg)
def subscribe(self, msg, subscriber):
# 订阅相关频道。
self.subscribers.setdefault(msg, []).append(subscriber)
def unsubscribe(self, msg, subscriber):
# 取消订阅
self.subscribers[msg].remove(subscriber)
def update(self):
for msg in self.msg_queue:
# 从消息列表中获取消息
for sub in self.subscribers.get(msg, []):
# 从订阅者中找到相关方
# 推送
sub.run(msg)
# 清空队列
self.msg_queue.clear()
class Publisher:
def __init__(self, msg_center):
self.provider = msg_center
def publish(self, msg):
# 发布者负责发布消息
self.provider.notify(msg)
class Subscriber:
"""
订阅者接受不了消息,处理消息。
"""
def __init__(self, name, msg_center):
self.name = name
self.provider = msg_center
def subscribe(self, msg):
self.provider.subscribe(msg, self)
def unsubscribe(self, msg):
self.provider.unsubscribe(msg, self)
def run(self, msg):
print(f'{self.name} got {msg}')
if __name__ == '__main__':
provider = Provider()
cctv = Publisher(provider)
xiaoming = Subscriber('xiaoming', provider)
huahua = Subscriber('huahua', provider)
dandan = Subscriber('dandan', provider)
huahua.subscribe('chiji')
dandan.subscribe('csgo')
xiaoming.subscribe('python')
cctv.publish('csgo')
provider.update()
registry / 出生登记
网传这种模式适合与singleton混用,如果登记处有这个人就复用,没有则生成一个单例。
在实际项目中,我个人更倾向于用来整理同类资源做反向查找。
这种模式上的整合可能要比 python 的 cls.__subclasses__()
更通俗一点
1 |
|
specification /规格
或者说是描述规则的模式。 常见的规则包括 and, or, is, not, specification 也需要实现这四个接口。
1 |
|
state / 状态机
适用于 状态较少的对象。利用状态来控制对象的表现形式。
1 |
|
strategy / 策略
用于拆分策略,方便算法的替换
对于python的类对象,可以使用 types.MethodType
方法将方法动态注册到实例。
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
# -*- coding: utf-8 -*-
import types
class StrategyExample:
def __init__(self, func=None):
self.name = 'Strategy Example 0'
if func is not None:
self.execute = types.MethodType(func, self)
def execute(self):
print(self.name)
def execute_replacement1(self):
print(self.name + ' from execute 1')
def execute_replacement2(self):
print(self.name + ' from execute 2')
if __name__ == '__main__':
strat0 = StrategyExample()
strat1 = StrategyExample(execute_replacement1)
strat1.name = 'Strategy Example 1'
strat2 = StrategyExample(execute_replacement2)
strat2.name = 'Strategy Example 2'
strat0.execute()
strat1.execute()
strat2.execute()
template / 模版
定义算法的框架,细节操作留给后人。
1
点右上角!
visitor / 来访者
1 |
|