不引人注目的轻反应系统

metapensiero.reactive的Python项目详细描述


一个不引人注目的轻反应系统

目标

这个包实现了一个框架,用于 functional reactive 编程 它希望使用和扩展简单,而不需要强制复杂 流、通道等概念是典型的 数据流 编程

要解释反应式编程,只需考虑一个电子表格,其中 有一个值单元格和一个公式单元格。后者更新 在适当的时候自动进行。

这个包实现了这一点。不,等等,不是电子表格,而是 一种表示生成结果的代码块(函数)的方法 (计算值)或副作用取决于其他值 所以当值改变时,代码块会自动 重新运行,

它的灵感来自于javascript的meteor"tracker"包,但是 为了更像蟒蛇,它从中分离出来。

用法

让我们看一个小例子:

cur_temp_fahrenheit=40defcur_temp_celsius(t_fahrenheit):return(t_fahrenheit-32)/1.8log=[]deflog_temp_celsius():log.append(cur_temp_celsius(cur_temp_fahrenheit))log_temp_celsius()assertlog==[4.444444444444445]

这是一小段代码,带有一个转换华氏温度的函数 摄氏度到摄氏度,然后将它们记录到列表中,但您可以想到 任何副作用。

现在,我们假设温度变化 无论何时记录。

为此,我们需要将温度转换成 reactive 值并让 跟踪器跟踪 这个值和使用它的计算。这边,当 值更改后,可以重新运行我们的 日志温度 做它的工作。所以我们主要通过使用getter和 一个setter,用于更改临时变量并在 发生这种情况,然后指示 跟踪器运行日志 函数以便它知道要重新运行什么。让我们看看:

frommetapensieroimportreactivetracker=reactive.get_tracker()dep=tracker.dependency()# this is just to handle setting a global varcur_temp_fahrenheit=[40]defget_temp_f():dep.depend()returncur_temp_fahrenheit[0]defset_temp_f(new):ifnew!=cur_temp_fahrenheit[0]:dep.changed()cur_temp_fahrenheit[0]=newdefcur_temp_celsius(t_fahrenheit):return(t_fahrenheit-32)/1.8log=[]deflog_temp_celsius(handle):log.append(cur_temp_celsius(get_temp_f()))handle=tracker.reactive(log_temp_celsius)assertlog==[4.444444444444445]set_temp_f(50)assertlog==[4.444444444444445,10.0]assertcur_temp_fahrenheit==50handle.stop()set_temp_f(60)assertlog==[4.444444444444445,10.0]assertcur_temp_fahrenheit==60

如你所见,当我们将当前温度设置为 值, 将重新运行日志温度,并在 日志 列表。我们仍然可以在不使用 跟踪器,在这种情况下,我们将有默认的,正常的,非反应的 行为。当我们使用tracker.reactive()时 通过运行 立即给定的函数。接下来,当反应源 更改后,跟踪器重新执行该函数,从而重新跟踪 可能不同的依赖项。 tracker.reactive() 返回 句柄,一个可用于停止 没有必要时的反应行为。相同的对象是 作为被跟踪函数的参数。

所举的例子确实很愚蠢,但却向你展示了 框架:

  • 代码更改很少;
  • 要学习的新概念非常少且简单;
  • 无需跟踪器参与,反应功能可单独运行 它们将作为普通代码运行,无需重构。

被跟踪的函数可以使用tracker.reactive() 本身,其中 外壳重新运行时,内部轨迹将停止。

由于使用getter和 塞特,我们怎么能避免呢?下面是使用 类:

frommetapensieroimportreactivetracker=reactive.get_tracker()cur_temp_fahrenheit=reactive.Value(40)defcur_temp_celsius(t_fahrenheit):return(t_fahrenheit-32)/1.8log=[]deflog_temp_celsius(handle):log.append(cur_temp_celsius(cur_temp_fahrenheit.value))handle=tracker.reactive(log_temp_celsius)assertlog==[4.444444444444445]cur_temp_fahrenheit.value=50assertlog==[4.444444444444445,10.0]handle.stop()cur_temp_fahrenheit.value=60assertlog==[4.444444444444445,10.0]

类也可以用作 类似于内置的支柱但只有一个 getter 函数。

使用值类的另一种方法是,通过 使用其 获取或设置该值,或与任何其他数据一样 班级成员。

a=Value()a.value=Trueasserta.value==TrueclassFoo(object):bar=Value()@Value()defzoo(self):# ... calc something usefulfoo=Foo()foo.bar=Trueassertfoo.bar==Trueanimal=foo.zoo

当在类"body a value 中使用时,将保存三元组 (依赖项, 计算,值) 每个实例,因此您必须将其纳入 帐户。 使用弱引用以避免保留 实例活动。

也有一个构造函数来构建反应 名称列表 类。

该框架还与 以另一个 greenlet 或 分别是任务。因为所有失效的计算 按顺序重新计算,避免悬浮 响应代码中的点,如调用 sleep() 函数或 执行 yield from await 语句。如果这是 不可避免的是,在 计算,命名为 suspend() 。使用它,代码块 在带有 语句的 内单独运行,并恢复跟踪 之后。

对于所有这些功能,请立即查看代码和测试。

测试

要运行测试,应在包根目录下运行以下命令:

python setup.py test

用python 2.7测试gevent和用python测试asyncio 3.5,运行:

pip install tox
tox

生成状态

https://travis-ci.org/azazazel75/metapensero.reactive.svg?branch=master

更改

0.1(2016-02-05)

  • 初始作用力。
  • 增加了tox和 gevent asyncio 测试
  • 文件的第一部分。

0.2(2016-02-05)

  • 小文档修复。

0.3(2016-02-10)

  • 更多测试。
  • 如果未定义生成器,则允许设置。
  • 值代码的重构。
  • 修复跟踪未激活时访问值时的行为。
  • 提供一种在计算if系统时停止跟踪的机制 需要暂停( gevent asyncio )。
  • 文档更新。
  • 代码现在在预生产环境中测试。

0.4(2016-02-11)

  • 在"删除"中修复一个小错误。

0.5(2016-02-11)

  • 只有在有依赖项时才需要刷新。

0.6(2016-02-13)

  • 文档更新。
  • 添加一个 @computation 装饰符。

欢迎加入QQ群-->: 979659372 Python中文网_新手群

推荐PyPI第三方库


热门话题
java kikoso/swipeable卡安卓   java致命异常:使用Firebase的令牌刷新器   如何捕获java。网SocketException:java中的管道断裂?   安卓 Flatter找不到捆绑的Java版本   java如何将容器添加到框架中?   java如何通过Jackson传递原始JSON?   java Thymeleaf变量超出范围?   Java泛型返回泛型参数化为更具体的两种类型?   java如何在Eclipse for Development模式下设置MySQL+Tomcat+GWT   Java小程序身份验证   java试图在spring中集成openId,但给出了BeanDefinitionParsingException   Java无法读取文本文件中的其他行   Rally项目使用JAVA API的修订历史记录   java Android改型v2插入失败错误403   spring boot应用程序中的java多个spring数据jpa模块(非spring boot)依赖关系?   java如何在设置登录和cookie后刷新GWTP应用程序?杜松子酒注射剂   java JDBC连接在Windows上非常慢,在Linux上很好