All posts by dotte

35个Python语言特征和编程技巧

从我开始学习python的时候,我就开始自己总结一个python小技巧的集合。后来当我什么时候在Stack Overflow或者在某个开源软件里看到一段很酷代码的时候,我就很惊讶:原来还能这么做!当时我会努力的自己尝试一下这段代码,直到我懂了它的整体思路以后,我就把这段代码加到我的集合里。这篇博客其实就是这个集合整理后一部分的公开亮相。如果你已经是个python大牛,那么基本上你应该知道这里面的大多数用法了,但我想你应该也能发现一些你不知道的新技巧。而如果你之前是一个c,c++,java的程序员,同时在学习python,或者干脆就是一个刚刚学习编程的新手,那么你应该会看到很多特别有用能让你感到惊奇的实用技巧,就像我当初一样。

每一个技巧和语言用法都会在一个个实例中展示给大家,也不需要有其他的说明。我已经尽力把每个例子弄的通俗易懂,但是因为读者对python的熟悉程度不同,仍然可能难免有一些晦涩的地方。所以如果这些例子本身无法让你读懂,至少这个例子的标题在你后面去Google搜索的时候会帮到你。

整个集合大概是按照难易程度排序,简单常见的在前面,比较少见的在最后。

1 拆箱

>>> a, b, c = 1, 2, 3
>>> a, b, c
(1, 2, 3)
>>> a, b, c = [1, 2, 3]
>>> a, b, c
(1, 2, 3)
>>> a, b, c = (2 * i + 1 for i in range(3))
>>> a, b, c
(1, 3, 5)
>>> a, (b, c), d = [1, (2, 3), 4]
>>> a
1
>>> b
2
>>> c
3
>>> d
4

2 拆箱变量交换

>>> a, b = 1, 2
>>> a, b = b, a
>>> a, b
(2, 1)

3 扩展拆箱(只兼容python3)

>>> a, *b, c = [1, 2, 3, 4, 5]
>>> a
1
>>> b
[2, 3, 4]
>>> c
5

4 负数索引

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a[-1]
10
>>> a[-3]
8

5 切割列表

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a[2:8]
[2, 3, 4, 5, 6, 7]

6 负数索引切割列表

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a[-4:-2]
[7, 8]

7 指定步长切割列表

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a[::2]
[0, 2, 4, 6, 8, 10]
>>> a[::3]
[0, 3, 6, 9]
>>> a[2:8:2]
[2, 4, 6]

8 负数步长切割列表

>>> a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
>>> a[::-1]
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> a[::-2]
[10, 8, 6, 4, 2, 0]

9 列表切割赋值

>>> a = [1, 2, 3, 4, 5]
>>> a[2:3] = [0, 0]
>>> a
[1, 2, 0, 0, 4, 5]
>>> a[1:1] = [8, 9]
>>> a
[1, 8, 9, 2, 0, 0, 4, 5]
>>> a[1:-1] = []
>>> a
[1, 5]

10 命名列表切割方式

>>> a = [0, 1, 2, 3, 4, 5]
>>> LASTTHREE = slice(-3, None)
>>> LASTTHREE
slice(-3, None, None)
>>> a[LASTTHREE]
[3, 4, 5]

11 列表以及迭代器的压缩和解压缩

>>> a = [1, 2, 3]
>>> b = ['a', 'b', 'c']
>>> z = zip(a, b)
>>> z
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> zip(*z)
[(1, 2, 3), ('a', 'b', 'c')]

12 列表相邻元素压缩器

>>> a = [1, 2, 3, 4, 5, 6]
>>> zip(*([iter(a)] * 2))
[(1, 2), (3, 4), (5, 6)]
 
>>> group_adjacent = lambda a, k: zip(*([iter(a)] * k))
>>> group_adjacent(a, 3)
[(1, 2, 3), (4, 5, 6)]
>>> group_adjacent(a, 2)
[(1, 2), (3, 4), (5, 6)]
>>> group_adjacent(a, 1)
[(1,), (2,), (3,), (4,), (5,), (6,)]
 
>>> zip(a[::2], a[1::2])
[(1, 2), (3, 4), (5, 6)]
 
>>> zip(a[::3], a[1::3], a[2::3])
[(1, 2, 3), (4, 5, 6)]
 
>>> group_adjacent = lambda a, k: zip(*(a[i::k] for i in range(k)))
>>> group_adjacent(a, 3)
[(1, 2, 3), (4, 5, 6)]
>>> group_adjacent(a, 2)
[(1, 2), (3, 4), (5, 6)]
>>> group_adjacent(a, 1)
[(1,), (2,), (3,), (4,), (5,), (6,)]

13 在列表中用压缩器和迭代器滑动取值窗口

>>> def n_grams(a, n):
...     z = [iter(a[i:]) for i in range(n)]
...     return zip(*z)
...
>>> a = [1, 2, 3, 4, 5, 6]
>>> n_grams(a, 3)
[(1, 2, 3), (2, 3, 4), (3, 4, 5), (4, 5, 6)]
>>> n_grams(a, 2)
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
>>> n_grams(a, 4)
[(1, 2, 3, 4), (2, 3, 4, 5), (3, 4, 5, 6)]

14 用压缩器反转字典

>>> m = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
>>> m.items()
[('a', 1), ('c', 3), ('b', 2), ('d', 4)]
>>> zip(m.values(), m.keys())
[(1, 'a'), (3, 'c'), (2, 'b'), (4, 'd')]
>>> mi = dict(zip(m.values(), m.keys()))
>>> mi
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}

15 列表展开

>>> a = [[1, 2], [3, 4], [5, 6]]
>>> list(itertools.chain.from_iterable(a))
[1, 2, 3, 4, 5, 6]
 
>>> sum(a, [])
[1, 2, 3, 4, 5, 6]
 
>>> [x for l in a for x in l]
[1, 2, 3, 4, 5, 6]
 
>>> a = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
>>> [x for l1 in a for l2 in l1 for x in l2]
[1, 2, 3, 4, 5, 6, 7, 8]
 
>>> a = [1, 2, [3, 4], [[5, 6], [7, 8]]]
>>> flatten = lambda x: [y for l in x for y in flatten(l)] if type(x) is list else [x]
>>> flatten(a)
[1, 2, 3, 4, 5, 6, 7, 8]

16 生成器表达式

>>> g = (x ** 2 for x in xrange(10))
>>> next(g)
0
>>> next(g)
1
>>> next(g)
4
>>> next(g)
9
>>> sum(x ** 3 for x in xrange(10))
2025
>>> sum(x ** 3 for x in xrange(10) if x % 3 == 1)
408

17 字典推导

>>> m = {x: x ** 2 for x in range(5)}
>>> m
{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}
 
>>> m = {x: 'A' + str(x) for x in range(10)}
>>> m
{0: 'A0', 1: 'A1', 2: 'A2', 3: 'A3', 4: 'A4', 5: 'A5', 6: 'A6', 7: 'A7', 8: 'A8', 9: 'A9'}

18 用字典推导反转字典

>>> m = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
>>> m
{'d': 4, 'a': 1, 'b': 2, 'c': 3}
>>> {v: k for k, v in m.items()}
{1: 'a', 2: 'b', 3: 'c', 4: 'd'}

19 命名元组

>>> Point = collections.namedtuple('Point', ['x', 'y'])
>>> p = Point(x=1.0, y=2.0)
>>> p
Point(x=1.0, y=2.0)
>>> p.x
1.0
>>> p.y
2.0

20 继承命名元组

>>> class Point(collections.namedtuple('PointBase', ['x', 'y'])):
...     __slots__ = ()
...     def __add__(self, other):
...             return Point(x=self.x + other.x, y=self.y + other.y)
...
>>> p = Point(x=1.0, y=2.0)
>>> q = Point(x=2.0, y=3.0)
>>> p + q
Point(x=3.0, y=5.0)

 

21 操作集合

>>> A = {1, 2, 3, 3}
>>> A
set([1, 2, 3])
>>> B = {3, 4, 5, 6, 7}
>>> B
set([3, 4, 5, 6, 7])
>>> A | B
set([1, 2, 3, 4, 5, 6, 7])
>>> A & B
set([3])
>>> A - B
set([1, 2])
>>> B - A
set([4, 5, 6, 7])
>>> A ^ B
set([1, 2, 4, 5, 6, 7])
>>> (A ^ B) == ((A - B) | (B - A))
True

22 操作多重集合

>>> A = collections.Counter([1, 2, 2])
>>> B = collections.Counter([2, 2, 3])
>>> A
Counter({2: 2, 1: 1})
>>> B
Counter({2: 2, 3: 1})
>>> A | B
Counter({2: 2, 1: 1, 3: 1})
>>> A & B
Counter({2: 2})
>>> A + B
Counter({2: 4, 1: 1, 3: 1})
>>> A - B
Counter({1: 1})
>>> B - A
Counter({3: 1})

23 统计在可迭代器中最常出现的元素

>>> A = collections.Counter([1, 1, 2, 2, 3, 3, 3, 3, 4, 5, 6, 7])
>>> A
Counter({3: 4, 1: 2, 2: 2, 4: 1, 5: 1, 6: 1, 7: 1})
>>> A.most_common(1)
[(3, 4)]
>>> A.most_common(3)
[(3, 4), (1, 2), (2, 2)]

24 两端都可操作的队列

>>> Q = collections.deque()
>>> Q.append(1)
>>> Q.appendleft(2)
>>> Q.extend([3, 4])
>>> Q.extendleft([5, 6])
>>> Q
deque([6, 5, 2, 1, 3, 4])
>>> Q.pop()
4
>>> Q.popleft()
6
>>> Q
deque([5, 2, 1, 3])
>>> Q.rotate(3)
>>> Q
deque([2, 1, 3, 5])
>>> Q.rotate(-3)
>>> Q
deque([5, 2, 1, 3])

25 有最大长度的双端队列

>>> last_three = collections.deque(maxlen=3)
>>> for i in xrange(10):
...     last_three.append(i)
...     print ', '.join(str(x) for x in last_three)
...
0
0, 1
0, 1, 2
1, 2, 3
2, 3, 4
3, 4, 5
4, 5, 6
5, 6, 7
6, 7, 8
7, 8, 9

26 可排序词典

>>> m = dict((str(x), x) for x in range(10))
>>> print ', '.join(m.keys())
1, 0, 3, 2, 5, 4, 7, 6, 9, 8
>>> m = collections.OrderedDict((str(x), x) for x in range(10))
>>> print ', '.join(m.keys())
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
>>> m = collections.OrderedDict((str(x), x) for x in range(10, 0, -1))
>>> print ', '.join(m.keys())
10, 9, 8, 7, 6, 5, 4, 3, 2, 1

27 默认词典

>>> m = dict()
>>> m['a']
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 'a'
>>>
>>> m = collections.defaultdict(int)
>>> m['a']
0
>>> m['b']
0
>>> m = collections.defaultdict(str)
>>> m['a']
''
>>> m['b'] += 'a'
>>> m['b']
'a'
>>> m = collections.defaultdict(lambda: '[default value]')
>>> m['a']
'[default value]'
>>> m['b']
'[default value]'

28 默认字典的简单树状表达

>>> import json
>>> tree = lambda: collections.defaultdict(tree)
>>> root = tree()
>>> root['menu']['id'] = 'file'
>>> root['menu']['value'] = 'File'
>>> root['menu']['menuitems']['new']['value'] = 'New'
>>> root['menu']['menuitems']['new']['onclick'] = 'new();'
>>> root['menu']['menuitems']['open']['value'] = 'Open'
>>> root['menu']['menuitems']['open']['onclick'] = 'open();'
>>> root['menu']['menuitems']['close']['value'] = 'Close'
>>> root['menu']['menuitems']['close']['onclick'] = 'close();'
>>> print json.dumps(root, sort_keys=True, indent=4, separators=(',', ': '))
{
    "menu": {
        "id": "file",
        "menuitems": {
            "close": {
                "onclick": "close();",
                "value": "Close"
            },
            "new": {
                "onclick": "new();",
                "value": "New"
            },
            "open": {
                "onclick": "open();",
                "value": "Open"
            }
        },
        "value": "File"
    }
}

29 对象到唯一计数的映射

>>> import itertools, collections
>>> value_to_numeric_map = collections.defaultdict(itertools.count().next)
>>> value_to_numeric_map['a']
0
>>> value_to_numeric_map['b']
1
>>> value_to_numeric_map['c']
2
>>> value_to_numeric_map['a']
0
>>> value_to_numeric_map['b']
1

30 最大和最小的几个列表元素

>>> a = [random.randint(0, 100) for __ in xrange(100)]
>>> heapq.nsmallest(5, a)
[3, 3, 5, 6, 8]
>>> heapq.nlargest(5, a)
[100, 100, 99, 98, 98]

31 两个列表的笛卡尔积

>>> for p in itertools.product([1, 2, 3], [4, 5]):
(1, 4)
(1, 5)
(2, 4)
(2, 5)
(3, 4)
(3, 5)
>>> for p in itertools.product([0, 1], repeat=4):
...     print ''.join(str(x) for x in p)
...
0000
0001
0010
0011
0100
0101
0110
0111
1000
1001
1010
1011
1100
1101
1110
1111

32 列表组合和列表元素替代组合

>>> for c in itertools.combinations([1, 2, 3, 4, 5], 3):
...     print ''.join(str(x) for x in c)
...
123
124
125
134
135
145
234
235
245
345
>>> for c in itertools.combinations_with_replacement([1, 2, 3], 2):
...     print ''.join(str(x) for x in c)
...
11
12
13
22
23
33

33 列表元素排列组合

>>> for p in itertools.permutations([1, 2, 3, 4]):
...     print ''.join(str(x) for x in p)
...
1234
1243
1324
1342
1423
1432
2134
2143
2314
2341
2413
2431
3124
3142
3214
3241
3412
3421
4123
4132
4213
4231
4312
4321

34 可链接迭代器

>>> a = [1, 2, 3, 4]
>>> for p in itertools.chain(itertools.combinations(a, 2), itertools.combinations(a, 3)):
...     print p
...
(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
(1, 2, 3)
(1, 2, 4)
(1, 3, 4)
(2, 3, 4)
>>> for subset in itertools.chain.from_iterable(itertools.combinations(a, n) for n in range(len(a) + 1))
...     print subset
...
()
(1,)
(2,)
(3,)
(4,)
(1, 2)
(1, 3)
(1, 4)
(2, 3)
(2, 4)
(3, 4)
(1, 2, 3)
(1, 2, 4)
(1, 3, 4)
(2, 3, 4)
(1, 2, 3, 4)

35 根据文件指定列类聚

>>> import itertools
>>> with open('contactlenses.csv', 'r') as infile:
...     data = [line.strip().split(',') for line in infile]
...
>>> data = data[1:]
>>> def print_data(rows):
...     print '\n'.join('\t'.join('{: <16}'.format(s) for s in row) for row in rows)
...
 
>>> print_data(data)
young               myope                   no                      reduced                 none
young               myope                   no                      normal                  soft
young               myope                   yes                     reduced                 none
young               myope                   yes                     normal                  hard
young               hypermetrope            no                      reduced                 none
young               hypermetrope            no                      normal                  soft
young               hypermetrope            yes                     reduced                 none
young               hypermetrope            yes                     normal                  hard
pre-presbyopic      myope                   no                      reduced                 none
pre-presbyopic      myope                   no                      normal                  soft
pre-presbyopic      myope                   yes                     reduced                 none
pre-presbyopic      myope                   yes                     normal                  hard
pre-presbyopic      hypermetrope            no                      reduced                 none
pre-presbyopic      hypermetrope            no                      normal                  soft
pre-presbyopic      hypermetrope            yes                     reduced                 none
pre-presbyopic      hypermetrope            yes                     normal                  none
presbyopic          myope                   no                      reduced                 none
presbyopic          myope                   no                      normal                  none
presbyopic          myope                   yes                     reduced                 none
presbyopic          myope                   yes                     normal                  hard
presbyopic          hypermetrope            no                      reduced                 none
presbyopic          hypermetrope            no                      normal                  soft
presbyopic          hypermetrope            yes                     reduced                 none
presbyopic          hypermetrope            yes                     normal                  none
 
>>> data.sort(key=lambda r: r[-1])
>>> for value, group in itertools.groupby(data, lambda r: r[-1]):
...     print '-----------'
...     print 'Group: ' + value
...     print_data(group)
...
-----------
Group: hard
young               myope                   yes                     normal                  hard
young               hypermetrope            yes                     normal                  hard
pre-presbyopic      myope                   yes                     normal                  hard
presbyopic          myope                   yes                     normal                  hard
-----------
Group: none
young               myope                   no                      reduced                 none
young               myope                   yes                     reduced                 none
young               hypermetrope            no                      reduced                 none
young               hypermetrope            yes                     reduced                 none
pre-presbyopic      myope                   no                      reduced                 none
pre-presbyopic      myope                   yes                     reduced                 none
pre-presbyopic      hypermetrope            no                      reduced                 none
pre-presbyopic      hypermetrope            yes                     reduced                 none
pre-presbyopic      hypermetrope            yes                     normal                  none
presbyopic          myope                   no                      reduced                 none
presbyopic          myope                   no                      normal                  none
presbyopic          myope                   yes                     reduced                 none
presbyopic          hypermetrope            no                      reduced                 none
presbyopic          hypermetrope            yes                     reduced                 none
presbyopic          hypermetrope            yes                     normal                  none
-----------
Group: soft
young               myope                   no                      normal                  soft
young               hypermetrope            no                      normal                  soft
pre-presbyopic      myope                   no                      normal                  soft
pre-presbyopic      hypermetrope            no                      normal                  soft
presbyopic          hypermetrope            no                      normal
from:http://www.techug.com/thirty-python-language-features-and-tricks-you-may-not-know

架构师到底是做什么的?

我要成为一个软件架构师。

对一个年轻的工程师来说,这是一个很好的目标。

我要领导一个团队,还要做所有关于数据库、框架和Web服务器的重要决定。

好吧,如果是这样,你就没必要成为一个软件架构师了。

当然有必要了!我要成为一个能够做所有重要决定的人。

这样很好,只是你没有列出哪些才是重要的决定。你刚才说的那些跟重要的决定没有什么关系。

你说什么?难道数据库不重要?你知道我们在数据库上面花了多少钱吗?

可能很多。不过数据库仍然不是最重要的。

你怎么能这么说呢?数据库可是整个系统的心脏啊!所有的数据都保存在这里,它们在这里被排序,被索引,被访问。如果没有数据库,整个系统就无法运作!

数据库只不过是一个IO设备,它提供了一些有用的工具对数据进行排序、查询,并生成报表,但这些工具都只是整个系统的附属品。

附属品?真是不可思议。

是的,附属品。你的系统业务逻辑或许会用到这些工具,但这些工具并非业务逻辑固有的组成部分。如果有必要,你可以随时替换掉这些工具,但业务逻辑还是那些业务逻辑。

好吧,不过如果把这些工具替换掉,我们就要重新实现业务逻辑了。

那是你的问题。

为什么这么说?

你认为业务逻辑依赖数据库,但实际上不是这样的。如果你的架构足够好,最起码业务逻辑不应该依赖数据库。

这太疯狂了。我怎么可能创建出不使用这些工具的业务逻辑?

我并没有说业务逻辑不要使用数据库工具,我的意思是它们不应该依赖这些工具。业务逻辑不应该知道使用的是哪一种数据库。

如果业务逻辑对数据库一无所知,它怎么使用这些工具呢?

依赖反转。你要让数据库依赖业务逻辑,而不是让业务逻辑依赖数据库。

你的话让人费解。

费解吗?我讲的可是软件架构。这个就是依赖反转原则,让下层策略来依赖上层策略。

那就更加费解了!既然上层策略(假设你指的是业务逻辑)要调用下层策略(假设你指的是数据库),那么就应该是上层策略依赖依赖下层策略,就像调用者依赖被调用者一样。这是众所周知的!

在运行时确实是这样的,但在编译时我们要把依赖反转过来。上层策略的代码里不要引用任何下层策略的代码。

拜托!不引用代码就无法调用它们。

当然可以调用了。面向对象就可以做到。

面向对象对真实世界进行建模,把数据和函数组合到对象里,把代码组织成直观的结构。

这是他们告诉你的吗?

所有人都知道的,这不是很明显的事情吗?

确实如此。不过,面向对象是可以做到不引用也能调用的。

好吧,那它是怎么做到的?

你应该知道,在面向对象系统里对象会给其它对象发送消息的,对吧?

是的,当然。

那么你就该知道,消息发送者是不知道消息接收者是什么类型的。

这要看使用的是哪一种语言了。在Java里,发送者最起码要知道接收者的基本类型。在Ruby里,发送者知道接收者一定会处理它所发送的消息。

是的。不过不管是哪一种情况,发送者都不知道接收者具体的类型。

嗯,是的。

所以发送者可以给接收者传递一个函数,让接收者执行这个函数,这样发送者就不需要知道接收者是什么类型了。

没错。我了解你的意思。不过发送者仍然依赖接收者。

在运行时确实是的,但在编译时不是这样的。发送者的代码里并没有引用接收者的代码。实际上,是接收者的代码依赖了发送者的代码。

啊!但发送者仍然会依赖接收者的类。

看来需要用代码来说明了,我用Java来写些代码。首先是发送者代码:

package sender;
public class Sender {
  private Receiver receiver;
  public Sender(Receiver r) {
    receiver = r;
  }
  public void doSomething() {
    receiver.receiveThis();
  }
  public interface Receiver {
    void receiveThis();
  }
}

下面是接收者代码:

package receiver;
import sender.Sender;
public class SpecificReceiver implements Sender.Receiver {
  public void receiveThis() {
    //这里会做一些有趣的事情
  }
}

可以看到,接收者代码依赖了发送者代码,也就是说SpecificReceiver依赖了Sender。同时可以看到,发送者代码对接收者代码一无所知。

哈,你作弊了。你把接收者的接口放到了发送者的类里了。

你开始明白了。

明白什么?

当然是架构原则啊。发送者持有接收者必须实现的接口。

如果这意味着我要使用内部类,那么……

使用内部类只是方法之一,还有其它的方法。

请等一下。最开始我们讨论的是数据库,那这些跟数据库又有什么关系呢?

让我们来看一下其它代码吧。首先是一个简单的业务逻辑

package businessRules;
import entities.Something;
public class BusinessRule {
  private BusinessRuleGateway gateway;
  public BusinessRule(BusinessRuleGateway gateway) {
    this.gateway = gateway;
  }
  public void execute(String id) {
    gateway.startTransaction();
    Something thing = gateway.getSomething(id);
    thing.makeChanges();
    gateway.saveSomething(thing);
    gateway.endTransaction();
  }
}

这个业务逻辑没有做什么事情啊。

这只是个例子。在实际实现业务逻辑的时候,不会有很多类似这样的类的。

好吧。那么Gateway是用来做什么的呢?

它为业务逻辑提供了所有访问数据的方法。下面是它的代码:

package businessRules;
import entities.Something;
public interface BusinessRuleGateway {
  Something getSomething(String id);
  void startTransaction();
  void saveSomething(Something thing);
  void endTransaction();
}

要注意,这个接口是在businessRules包里面的。

好吧。那Something这个类又是用来做什么的呢?

它代表一个简单的业务对象。我把它放在另一个叫entities的包里。

package entities;
public class Something {
  public void makeChanges() {
    //...
  }
}

最后需要实现BusinessRuleGateway接口,这个实现类会知道相关的数据库细节:

package database;
import businessRules.BusinessRuleGateway;
import entities.Something;
public class MySqlBusinessRuleGateway implements BusinessRuleGateway {
  public Something getSomething(String id) {
    // 从MySQL里读取一些数据
  }
  public void startTransaction() {
    // 开始一个事务
  }
  public void saveSomething(Something thing) {
    // 把数据保存到MySQL
  }
  public void endTransaction() {
    // 结束事务
  }
}

可以看到,业务逻辑是在运行时对数据库进行调用的。而在编译时,是database包引用了businessRules包。

好吧,我想我明白了。你用多态性隐藏了数据库实现。不过在业务逻辑里,仍然引用了数据库的工具接口。

不,不是这样的。我们并没有打算为业务逻辑提供所有的数据库工具接口,而是业务逻辑创建了它们所需要的接口。在实现这些接口的时候,可以调用相应的工具。

嗯,这样的话,如果业务逻辑需要所有的工具,那么你必须把所有工具都放到Gateway接口里。

哈,我觉得你还是没有明白。

不明白什么?我觉得已经很清楚了。

每个业务逻辑只定义它所需要的接口。

等等,什么意思?

这个叫作接口分离原则。每个业务逻辑只使用一部分数据库工具,所以每个业务逻辑只定义能够满足需要的接口。

这样的话,你就会有很多接口,而且有很多实现类。

哈,是的。你开始明白了。

这样子很浪费时间!我为什么要这样做呢?

这样做是为了让代码更干净,并且节省时间。

算了吧,这样只会增加更多的代码。

相反,这其实是很重要的架构决定,这跟你之前所说的那些所谓的重要决定是不一样的。

什么意思?

还记得你刚开始说你要成为一个软件架构师吗?你还想要做所有重要的决定?

是啊,我是这么想过。

你想做所有关于数据库、Web服务和框架的决定。

是啊,而你却说它们都不重要,还说它们其实跟重要的决定不相干。

没错,它们确实跟重要的决定不相干。一个软件架构师真正要做的重要决定都在数据库、Web服务器和框架之外。

但首先要先决定用什么数据库、Web服务器或框架啊!

what-architect-do 架构师

不,实际上应该在开发后期才开始做这些事情——在你掌握了更多信息之后。
哀,当架构师草率地决定要使用一个数据库,后来却发现使用文件系统效率更高。
哀,当架构师草率的决定使用一个Web服务器,后来却发现团队需要的不过是一个socket借口。
哀,当架构师草率地决定使用一个框架,后来却发现框架提供的功能是团队不需要的,反而给团队带来了诸多约束。
幸,当架构师在掌握了足够多的信息后才决定该用什么数据库、Web服务器或框架。
幸,当架构师为团队鉴别出运行缓慢、耗费资源的IO设备和框架,这样他们就可以构建飞速运行的轻量级测试环境。
幸,当架构师把注意力放在那些真正重要的事情上,并把那些不重要的事情放在一边。

我完全不知道你在说什么了。

from:http://www.infoq.com/cn/news/2016/12/What-architect-do

12580

工商银行 95588

建设银行 95533

农业银行 95599

中国银行 95566

交通银行 95559

浦发银行 95528

民生银行 95568

兴业银行 95561

中信银行 95558

深圳发展银行 95501

华夏银行 95577

招商银行 95555

广发银行 95508

光大银行 95595

生命人寿95535

中国人保 95518

中国人寿 95519

太平洋保险 95500

中国平安保险集团 95511

新华人寿保险 95567

医疗保险查询 96102

泰康人寿保险 95522

匪警台 110

火警台 119

医疗急救台 120

交通事故报警台 122

水上求救 12395

短信报警号码 12110

非紧急救助中心 12345

职务犯罪举报 12309

天气预报 12121

报时台 12117

供电服务热线 95598

劳保政策咨询 12333

投诉举报

消费者投诉热线 12315

价格投诉热线 12358

质量投诉 12365

环保投诉 12369

税务投诉 12366

公共卫生监督 12320

电信投诉 12300

市长热线 12366

法律援助 12351

妇女维权 12338

民工维权 12333

铁路航空

铁路 12306

国航 4008100999

海航 950718

南航 4006695539

东航 95530

深航 4008895080

厦航 95557

山航 4006096777

快递客服

申通快递 4008895543

EMS 4008100999

顺丰速运 400-811-1111

圆通速递 021-69777888

中通速递 021-39777777

韵达快运 021-39207888

天天快递 021-67662333

汇通快运 021-62963636

速尔快递 4008822168

顺丰速运 400-811-1111

德邦物流 4008305555

宅急送 4006789000

中铁快运 95572

鑫飞鸿快递 021-69781999

UPS 4008208388

FedEx(联邦快递) 4008861888

通讯客服

中国移动 10086

中国联通 10010

中国电信 10000

中国网通 10060

中国铁通 10050

中国邮政 11185

查号台 114

移动信息查询 12580

联通114 116114

电信114 118114

电话障碍申告台 112

中国电信IP接入号 17900

联通IP接入号 17910

移动IP接入号 17951

网通IP接入号 17960

铁通IP接入号 17990

联通长途接入号 193

网通长途接入号 196

铁通长途接入号 068

网上购物

淘宝网 0571-88158198

京东商城 4006065500

当当网 4007116699

卓越网 4008105666

拍拍网 0755-83762288

凡客诚品 4006006888

拉手网 4000517317

美团 4006605335

24券 4006662424

糯米网 4006500117

满座网 4006858666

窝窝团 4001015555

售后服务

苹果 4006272273

诺基亚 4008800123

三星 4008105858

摩托罗拉 8008105050

索爱 4008100000

联想 8008108888

戴尔 8008580888

索尼 8008209000

飞利浦 8008201201

松下 8008100781

东芝 8008108208

TCL 4008123456

外卖订餐

麦当劳 4008517517

肯德基 4008823823

必胜客 4008123123

真功夫 4006927927

租车电话

神州租车 4006166666

一嗨租车 4008886608

易到租车 4001111777

记住这些电话有时比到法院更有效

中央电视台《焦点访谈》:

010-68579889北京复兴路11号中央电视台邮编:100859

中央电视台《东方时空》:

010-68508738

中央电视台《实话实说》:

010-63984662

中央电视台《面对面》 :

010-63984655

中央电视台《新闻调查》:

010-68579889转198

中央电视台《今日说法》:

010-68579889-166

凤凰台总机 010-68977288

人民日报新闻线索:010-65368383

解放日报新闻热线:8621-63523600

新华社新闻热线010-63073111 / 3222 010-63076206 / 010-63074267

中组部反映违反选人用人方面的问题举报: 电话:区号+12380

高检检察机关超期羁押举报 电话:

010-68650468 / 010-65252000

高检群众举报职务犯罪电话:

010-65252000

邮箱:cyjb@spp.gov.cn

高检减刑、假释、保外就医专项检查活动举报电话:010-68650468

国家发改委教育乱收费举报 电话:

010-68502937 / 010-66096145

0371-5900737 / 0371-5959578

国家发改委重大建设项目违规举报:010-68501111

农民工工资拖欠问题举报:

010-68304532

公安部经济犯罪举报中心:

010-65204333

公安部打拐举报电话:

010-84039250

国土资源部中国土地矿产法律热线:16829999

国土资源部全国建设系统服务热线:12319

水利部水利工程建设举报:

010-63205050

公安部扫黄打非举报电话:

010-65254722

农业部农业安全生产事故和紧急事件举报电话:010-64192512

中国消协农机产品质量投诉站投诉:010-67347472

消费者申诉举报电话:12315

农业部农业部种子案件举报电话:

010-64192079、64194511

农业部农药案件举报:

010-64192810、64194066

统计局统计违法举报:

010-68573311转88123

审计署水利建设资金举报:

010-68301241、 010-68301802(自动传真)

税务总局 税务违法案件举报中心电话:010-63417425、010-63543740、010-63417436 传真:010-63543711

电监会电石、铁合金和焦炭行业用电及执行电价情况监督举报电话:

010-66597385、010-66597388
香港电视广播有限公司驻北京记

者站(香港无线电视台)地址:北京市朝阳区齐家园外交公寓9号楼6层5号邮编:100600电话:65326388 13511060383传真:65326380

香港有线电视驻北京记者站地址:北京市朝阳区齐家园外交公寓11号楼7层1号邮编:100600电话:85321643 13511065495传真:85321645

凤凰卫视有限公司驻北京记者站地址:北京市海淀区海淀路165号南门凤凰会馆506室邮编:100080电话:62610055——517传真:62510320

亚洲电视驻北京记者站电话:13602615512

香港电台驻北京记者站地址:北京市朝阳区齐家园外交公寓8号楼131号邮编:100600电话:85322215 13911759443传真:85322615

香港商业电台驻北京记者站地址:北京市朝阳区齐家园外交公寓9号楼53号邮编:100600电话:85322838 13511065233传真:85322839

香港南华早报驻北京记者站地址:北京市朝阳区光华路1号嘉里中心裙楼202A邮编:100020电话:85296036传真:85296037

香港大公报驻京记者站地址:北京阜城门外大街11号国宾写字楼608室邮编:100037电话:68001032传真:68001036

香港文汇报驻北京记者站地址:北京东城区安定门外大街185号京宝大厦418室邮编:100011电话:64401818传真:64401736

香港商报驻北京记者站地址:北京市东城区炮局二条1号邮编:100007电话:84055652传真:84044033

香港明报驻北京记者站地址:北京市朝阳区齐家园外交公寓10号楼31室邮编:100600电话:85321937 1391006233
新闻日报 Newsday办 公 室: 建国门外外交公寓7-1-133邮政编码: 100600电话: 65323443传真: 65324732

Percolator, Dremel and Pregel: Alternatives to Hadoop

Hadoop (MapReduce where code is turned into map and reduce jobs, and Hadoop runs the jobs) is great at crunching data yet inefficient for analyzing data because each time you add, change or manipulate data you must stream over the entire dataset.

In most organizations, data is always growing, changing, and manipulated and therefore time to analyze data significantly increases.

As a result, to process large and diverse data sets, ad-hoc analytics or graph data structures, there must be better alternatives to Hadoop / MapReduce.

Google (architect of Hadoop / MapReduce) thought so and architected a better, faster data crunching ecosystem that includes Percolator, Dremel and Pregel. Google is one of the key innovative leaders for large scale architecture.

Percolator is a system for incrementally processing updates to a large data sets. By replacing a batch-based indexing system with an indexing system based on incremental processing using Percolator, you significantly speed up the process and reduce the time to analyze data.

Percolator’s architecture provides horizontal scalability and resilience. Percolator allows reducing the latency (time between page crawling and availability in the index) by a factor of 100. It allows simplifying the algorithm. The big advantage of Percolator is that the indexing time is now proportional to the size of the page to index and no more to the whole existing index size.

See: http://research.google.com/pubs/pub36726.html

Dremel is for ad hoc analytics. Dremel is a scalable, interactive ad-hoc query system for analysis of read-only nested data. By combining multi-level execution trees and columnar data layout, it is capable of running aggregation queries over trillion-row tables in seconds. The system scales to thousands of CPUs and petabytes of data and allows analysts to scan over petabytes of data in seconds to answer queries. Dremel is capable of running aggregation queries over trillions of rows in seconds and thus is about 100 times faster than MapReduce.

Dremel’s architecture is similar to Pig and Hive. Yet while Hive and Pig rely on MapReduce for query execution, Dremel uses a query execution engine based on aggregator trees.

See: http://research.google.com/pubs/pub36632.html

Pregel is a system for large-scale graph processing and graph data analysis. Pregel is designed to execute graph algorithms faster and use simple code. It computes over large graphs much faster than alternatives, and the application programming interface is easy to use.

Pregel is architected for efficient, scalable and fault-tolerant implementation on clusters of thousands of commodity computers, and its implied synchronicity makes reasoning about programs easier. Distribution-related details are hidden behind an abstract API. The result is a framework for processing large graphs that is expressive and easy to program.

See: http://kowshik.github.com/JPregel/pregel_paper.pdf

from:http://www.analyticbridge.com/profiles/blogs/percolator-dremel-and-pregel-alternatives-to-hadoop

InfoQ2016北京架构峰会

http://bj2016.archsummit.com/schedule