接口分解行为到可组合的单元,而不是显式的继承层次结构是一个Python没有解决好的问题,经常导致噩梦般的复杂的使用mixin。然而通过使用ABC模组模仿静态定义的接口可以缓解这个问题。 import heapq import collections class Heap(collections.Sized): def __init__(self, initial=None, key=lambda x:x): self.key = key if initial: self._data = [(key(item), item) for item in initial] heapq.heapify(self._data) else: self._data = [] def pop(self): return heapq.heappop(self._data)[1] def push(self, item): heapq.heappush(self._data, (self.key(item), item)) def len(self): return len(self._data) from abc import ABCMeta, abstractmethod class Eq(object): __metaclass__ = ABCMeta @classmethod def __subclasshook__(cls, C): if cls is Eq: for B in C.__mro__: if "eq" in B.__dict__: if B.__dict__["eq"]: return True break return NotImplemented def eq(a, b): if isinstance(a, Eq) and isinstance(b, Eq) and type(a) == type(b): return a.eq(b) else: raise NotImplementedError class Foo(object): def eq(self, other): return True class Fizz(Foo): pass class Bar(object): def __init__(self, val): self.val = val def eq(self, other): return self.val == other.val print eq(Foo(), Foo()) print eq(Bar(1), Bar(1)) print eq(Foo(), Bar(1)) print eq(Foo(), Fizz()) |
然后扩展这种类型的接口概念到多参数的函数,使得查询__dict__越来越可能发生,在组合的情况下很脆弱。问题的关键是分解所有的事情到单一类型不同的接口,当我们真正想要的是声明涵盖一组多类型的接口时。OOP中的这种缺点是 表达式问题的关键。 诸如Scala、Haskell和Rust这样的语言以trait和typeclass这样的形式提供该问题的解决方案。例如Haskell可以自动地为所有类型的交叉产品推导出微分方程。 instance (Floating a, Eq a) => Floating (Dif a) where pi = C pi exp (C x) = C (exp x) exp (D x x') = r where r = D (exp x) (x' * r) log (C x) = C (log x) log p@(D x x') = D (log x) (x' / p) sqrt (C x) = C (sqrt x) sqrt (D x x') = r where r = D (sqrt x) (x' / (2 * r)) |
异步编程在这个主题下,我们还是有很多缝缝补补的解决方案,解决了部分的问题,但是引入了一整与常规Python背道而驰的套限制和模式。Gevent通过剪接底层C堆栈保持了Python自己的一致性。生成的API非常优雅,但是使得推理控制流和异常非常复杂。 import gevent def foo(): print('Running in foo') gevent.sleep(0) print('Explicit context switch to foo again') def bar(): print('Explicit context to bar') gevent.sleep(0) print('Implicit context switch back to bar') gevent.joinall([ gevent.spawn(foo), gevent.spawn(bar), ])
控制流展示在下面: 通过对标准库相当不优美的缝缝补补(monkey-patching),我们可以模仿Erlang式带有异步进入点和内部状态的actor行为: import gevent from gevent.queue import Queue from SimpleXMLRPCServer import SimpleXMLRPCServer class Actor(object): _export = [ 'push', ] def __init__(self, address): self.queue = Queue() self._serv = SimpleXMLRPCServer(address, allow_none=True, logRequests=False) self.address = address for name in self._export: self._serv.register_function(getattr(self, name)) def push(self, thing): self.queue.put(thing) def poll(self): while True: print(self.queue.get()) def periodic(self): while True: print('PING') gevent.sleep(5) def serve_forever(self): gevent.spawn(self.periodic) gevent.spawn(self.poll) self._serv.serve_forever() def main(): from gevent.monkey import patch_all patch_all() serve = Actor(('', 8000)) serve.serve_forever() |
DSLsZ3工程是嵌在Python对象层的扩展API。用Z3的实例来解决N皇后问题可以被描述为Python表达式和扩展SMT来解决问题: from Z3 import * Q = [ Int('Q_%i' % (i + 1)) for i in range(8) ] # Each queen is in a column {1, ... 8 } val_c = [ And(1 <= Q[i], Q[i] <= 8) for i in range(8) ] # At most one queen per column col_c = [ Distinct(Q) ] # Diagonal constraint diag_c = [ If(i == j, True, And(Q[i] - Q[j] != i - j, Q[i] - Q[j] != j - i)) for i in range(8) for j in range(i) ] solve(val_c + col_c + diag_c) 在Theano,SymPy,PySpark中的其它工程大量使用基于Python表达式的重载操作符的方式。 from sympy import Symbol from sympy.logic.inference import satisfiable x = Symbol('x') y = Symbol('y') satisfiable((x | y) & (x | ~y) & (~x | y)) |
参与翻译(4人):袁不语, 小panda, Garfielt, yale8848
本文转自:开源中国社区 [http://www.oschina.net]
本文标题:飞跃式发展的后现代 Python 世界
本文地址:http://www.oschina.net/translate/postmodern-python