不需要每次调用import语句就能执行Python代码

5
这是一个Python脚本示例。如何从命令行多次运行此脚本,以便不必每次调用导入语句?导入语句需要太长时间来加载。
import arcpy
val = arcpy.GetCellValue_management("D:\dem-merged\lidar_wsg84", "-95.090174910630012 29.973962146120652", "")
print str(val)

如果不导入arcpy,你如何期望获得它所包含的功能? - Keith
我正在寻找一种导入或加载脚本的方法。该脚本将从另一个程序中调用,通过在命令行上发出“python script.py”并读取其输出。在脚本中进行导入会导致很多延迟。 - Shaunak
其他程序是用哪种语言编写的? - Gerrat
我正在尝试从Ruby on Rails Web服务访问Python脚本。 - Shaunak
7个回答

6
如果您严格要求这个脚本“从另一个程序中调用,通过在命令行上发出'python script.py'”,那么这个问题是没有解决方案的。 如果您只想进行一次“重导入”,则必须仅启动一次python脚本。 考虑启动一个守护进程,它将启动一次,然后处理来自其他程序的调用。这样,所有初始化只需要做一次,下一次调用就会很快。 如果您将Python代码分为两部分(第一部分为守护进程,第二部分为守护进程客户端),则可以从另一个程序调用“python client.py”,但实际计算将由守护进程执行,它仅启动了一次。
例如:
daemon.py
import socket
#import arcpy

def actual_work():
    #val = arcpy.GetCellValue_management("D:\dem-merged\lidar_wsg84", "-95.090174910630012 29.973962146120652", "")
    #return str(val)
    return 'dummy_reply'


def main():
    sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
    try:
        sock.bind( ('127.0.0.1', 6666) )

        while True:
            data, addr = sock.recvfrom( 4096 )
            reply = actual_work()
            sock.sendto(reply, addr)
    except KeyboardInterrupt:
        pass
    finally:
        sock.close()


if __name__ == '__main__':
    main()

client.py

import socket
import sys


def main():
    sock = socket.socket( socket.AF_INET, socket.SOCK_DGRAM )
    sock.settimeout(1)
    try:
        sock.sendto('', ('127.0.0.1', 6666))
        reply, _ = sock.recvfrom(4096)
        print reply
    except socket.timeout:
        sys.exit(1)
    finally:
        sock.close()


if __name__ == '__main__':
    main()

比较fastcgi、spamassassin的spamd或emacsclient。也许Pyro可以帮助进行分离。 - Yann Vernier
Pyro看起来很不错,但我认为它有些过度了。使用普通的UDP套接字是从本地守护程序获取短文本数据的最简单方法。 - Alex Laskin

2
几乎是不可能的。一旦你离开解释器,导入的模块将不再存在于内存中。这类似于要求Firefox将大型网页保存在内存中,因为读取缓存速度太慢。一旦关闭Firefox(或Python),RAM中的任何内容基本上都会消失。
你可以加快加载时间,但有风险。通过运行
python -O 

你可以让它运行得更快一些。你也可以再添加一个'O'来使其运行速度稍微快一些。然而,这可能会导致某些程序出现错误,并且并不总是有效。
你可以通过复制所需的函数到你的程序中来实现。
from arcpy import <what you need>

这可能会使事情稍微快一些。


1
据我所知,该模块只会被导入一次。因此,如果你这样做:
import a
import a

它只会被导入一次。因此,与其多次运行脚本,也许你可以将其更改为一次性制作所有副本。

如果你必须多次运行这个特定的脚本,我认为你无法避免导入并且每次都必须进行导入。


我需要在命令提示符上多次运行同一脚本。无法在一个会话中完成。 - Shaunak

1
我能想到的一个解决方案是拥有一个持续运行的服务器进程来执行实际工作,而从命令行调用的脚本仅向该脚本发出请求。这需要相当多的工作,但可能值得这样做。

我已经尝试过了。但是它还有另一个问题。这是链接http://stackoverflow.com/questions/6687819/perfectly-running-python-script-gives-error-when-run-from-web-py - Shaunak

0
我能想到的唯一解决方案是手动将您需要执行的个别函数复制到您的代码中,如果需要执行的内容足够小。
如果您需要如何操作的帮助,请在评论中提问。

0

简单。

使用cmd模块编写自己的简单shell,并使用runpy模块来运行你的脚本。在shell程序中导入你的大型模块,并通过init_globals将其传递给程序。

查看http://pypi.python.org/pypi/cmd2/上的文档,你应该很清楚如何编写自己的简单shell,即使它只有两个命令,一个用于编辑文件,一个用于运行文件。

runpy是Python标准库的一部分http://docs.python.org/library/runpy.html,你可能不需要它,但知道导入和模块加载机制可以被你的命令shell控制甚至修改是很有用的。

你是否曾经想过当你执行像 var1 = 25 这样的语句时,“var1”这个名字去了哪里?当你稍后执行 print var1 时,Python 如何找到 var1 所指的内容?答案是这些名字在一个字典中,如果你理解 Python 字典的含义和功能,它似乎是将名称与值连接起来的显而易见的解决方案。但还有更多。Python 可以有很多命名空间,你可以像操作字典一样操作这些命名空间。阅读这篇文章http://www.diveintopython.net/html_processing/locals_and_globals.html 以了解 localsglobals 命名空间。这里还有另一篇讨论http://lucumr.pocoo.org/2011/2/1/exec-in-python/,可以帮助你更好地理解。

尝试使用exec,就像在这个问题globals and locals in python exec()中一样,直到你理解它的工作原理。然后构建您的命令行壳以在开始时导入模块,并编写脚本仅在模块不可用时才导入该模块。当从您的shell内运行脚本时,该模块已经存在。


抱歉,我知道这是一个旧的帖子,但是我之前不知何故错过了你的回答。你能详细解释一下你的答案吗?我不确定我是否理解了它。虽然我不是真正的Python专家,但你的解决方案肯定比运行我的服务的服务器更好。 - Shaunak

0

根据您的使用情况(从Ruby on Rails Web服务调用),最简单的方法之一是使用XML-RPC。使用Python标准库中的SimpleXMLRPCServer,然后使用Ruby客户端(Ruby似乎在标准库中有xmlrpc)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接