如何确保python函数仅根据其输入生成其输出?

时间:2014-10-10 15:35:29

标签: python database functional-programming filesystems httpwebrequest

要生成输出,函数通常只使用其参数的值。但是,在某些情况下,生成其输出的函数会从文件系统或数据库或Web中读取内容。我希望有一种简单可靠的方法来确保不会发生类似的事情。

我看到的一种方法是创建一个python库的白名单,可用于从文件系统,数据库或Web中读取。但如果它是要走的路,我在哪里可以得到这个(可能是巨大的)列表。此外,我不想仅仅因为它可以用来从文件系统读取而禁用整个库。例如,我希望用户能够使用pandas库(存储和操作表格数据)。我只是不希望他们能够使用这个库从文件系统中读取数据。

这个问题有解决方案吗?

3 个答案:

答案 0 :(得分:8)

答案是。您正在寻找的是一个测试functional purity的函数。但是,正如本代码所示,没有办法保证实际上没有副作用被调用。

class Foo(object):
    def __init__(self, x):
        self.x = x
    def __add__(self, y):
        print("HAHAHA evil side effects here...")
        # proceed to read a file and do stuff
        return self

# this looks pure...
def f(x): return x + 1

# but really...
>>> f(Foo(1))
HAHAHA evil side effects here...

由于对象可以重新定义其行为(字段访问,调用,运算符重载等)的综合方式,因此您始终可以传递使纯函数不纯的输入。因此,唯一的纯函数就是那些对它们的参数一无所知的函数......一类通常不太有用的函数。

当然,如果您可以指定其他限制,这将变得更容易。

答案 1 :(得分:4)

即使删除所有模块和所有功能,也可以破坏所需的限制。如果代码可以使用任意简单对象的属性,例如,代码可以访问文件。数字为零。

(0).__class__.__base__.__subclasses__()[40]('/etc/pas'+'swd')

索引40是个体的,非常典型的Python 2.7,但子类<type 'file'>的索引很容易找到:

[x for x in (1).__class__.__base__.__subclasses__()if'fi'+'le'in'%s'%x][0](
 '/etc/pas'+'swd')

白名单和黑名单的任何组合都是不安全和/或限制太多。 pypy sandbox 在没有妥协的情况下非常强大:

  

...这个子进程可以运行任意不受信任的Python代码,但所有   它的输入/输出被序列化为stdin / stdout管道而不是   直接表演。外部进程读取管道并决定哪个   允许或不允许命令(沙盒),甚至重新解释它们   不同...

基于 seccomp 内核功能的解决方案也足够安全。 (blog


  

我想确保将来该功能会生成相同的功能   今天输出。

编写具有难以重现的结果的功能很容易,并且不容易预防:

class A(object):
    "This can be any very simple class"
    def __init__(self, x):
        self.x = x
    def __repr__(self):
        return repr(self.x)

def strange_function():
    # You get a different result probably everytimes.
    return list(set(A(i) for i in range(20)))

>>> strange_function()
[1, 18, 12, 5, 16, 15, 8, 2, 14, 0, 6, 19, 13, 11, 10, 9, 17, 3, 7, 4]
>>> strange_function()
[0, 9, 14, 3, 17, 5, 6, 11, 8, 1, 15, 7, 12, 13, 2, 10, 16, 4, 19, 18]

...即使你删除依赖于时间的每个时间,随机数生成器,基于散列函数的顺序等,也很容易编写有时超过可用内存或超时限制的函数,有时会给出结果。


编辑:
罗曼,你最近写道,你确信你可以相信用户。然后存在现实的解决方案。它是通过将函数记录到文件并在运行远程IPython notebook的虚拟机上验证它来验证函数的输入和输出(很好的简短教程视频,支持远程计算开箱即用,重启一秒钟内从浏览器通过Web文档菜单进行后端服务,而不会丢失笔记本(html文档)中的数据(输入/输出),因为它是由我们的活动一步一步地动态创建的,触发调用远程后端的javascript。

在发现差异之前,您不必对内部调用感兴趣,只需对全局输入和输出感兴趣。虚拟机应该能够独立且可重复地验证结果。配置防火墙,机器接受您的连接,但无法启动传出连接。配置文件系统,当前用户无法保存任何数据,因此除软件组件外,它们不存在。禁用数据库服务。以随机顺序验证结果输入/输出或在不同端口上启动两个IPython笔记本服务,并为笔记本上的每个命令行选择随机后端,或者在任何重要事件之前频繁重启后端进程。如果发现差异,请调试代码并进行修复。

您可以在没有&#34;笔记本电脑的情况下实现自动化。在您不需要交互性之后,最终只能使用IPython远程计算。

答案 2 :(得分:4)

您想要的是沙盒或受限制的Python。

两者都死了。

今天最接近功能的是http://pypy.readthedocs.org/en/latest/sandbox.html,但是最新的版本实际上是3年。