10

是否可以import使用http( s) ftpsmb或任何其他协议通过 Internet 访问 Python 模块?如果是这样,怎么做?如果不是,为什么?

我想这是关于让 Python 更多地使用一种协议(读取文件系统)并使其也能够使用其他协议。是的,我同意它会慢很多倍,但是一些优化和更大的未来带宽肯定会平衡它。

例如:

import site

site.addsitedir("https://bitbucket.org/zzzeek/sqlalchemy/src/e8167548429b9d4937caaa09740ffe9bdab1ef61/lib")

import sqlalchemy
import sqlalchemy.engine
4

4 回答 4

4

原则上,是的,但是所有支持这一点的内置工具都通过文件系统。

为此,您将不得不从任何地方加载源代码,使用 编译它compile,然后exec使用__dict__新模块的 编译它。见下文。

我已经从互联网上留下了实际抓取的文本,并将解析 uris 等作为读者的练习(对于初学者:我建议使用requests

pep 302术语中,这将是函数背后的实现loader.load_module(参数不同)。有关如何将其与import语句集成的详细信息,请参阅该文档。

import imp
modulesource = 'a=1;b=2' #load from internet or wherever
def makemodule(modulesource,sourcestr='http://some/url/or/whatever',modname=None):
    #if loading from the internet, you'd probably want to parse the uri, 
    # and use the last part as the modulename. It'll come up in tracebacks
    # and the like.
    if not modname: modname = 'newmodulename'
    #must be exec mode
    # every module needs a source to be identified, can be any value
    # but if loading from the internet, you'd use the URI
    codeobj = compile(modulesource, sourcestr, 'exec')
    newmodule = imp.new_module(modname)
    exec(codeobj,newmodule.__dict__)
    return newmodule
newmodule = makemodule(modulesource)
print(newmodule.a)

此时newmodule已经是范围内的模块对象,因此您不需要导入它或任何东西。

modulesource = '''
a = 'foo'
def myfun(astr):
    return a + astr
'''
newmod = makemodule(modulesource)
print(newmod.myfun('bat'))

ideone在这里:http: //ideone.com/dXGziO

使用 python 2 测试,应该可以使用 python 3(使用文本兼容的打印;使用类似函数的 exec 语法)。

于 2013-09-11T19:20:06.783 回答
4

另一个版本,

我喜欢这个答案。应用它时,我对其进行了一些简化——类似于javascriptinclude over HTTP的外观和感觉。

这是结果:

import os
import imp
import requests

def import_cdn(uri, name=None):
    if not name:
        name = os.path.basename(uri).lower().rstrip('.py')

    r = requests.get(uri)
    r.raise_for_status()

    codeobj = compile(r.content, uri, 'exec')
    module = imp.new_module(name)
    exec (codeobj, module.__dict__)
    return module

用法:

redisdl = import_cdn("https://raw.githubusercontent.com/p/redis-dump-load/master/redisdl.py")

# Regular usage of the dynamic included library
json_text = redisdl.dumps(host='127.0.0.1')
  • 提示- 将import_cdn函数放在一个公共库中,这样你就可以重复使用这个小函数
  • 请记住,当没有通过 http 连接到该文件时,它将失败
于 2015-12-28T10:01:30.747 回答
1

这似乎是一个自写导入钩子的用例。在PEP 302中查找它们的工作原理。

本质上,您必须提供一个 finder 对象,而该对象又提供一个 loader 对象。乍一看,我不明白这个过程(否则我会更明确),但 PEP 包含实现这些东西所需的所有细节。

于 2013-09-11T19:57:09.667 回答
0

正如glglgl所拥有的那样,这个导入钩子已经在一个名为httpimport. 它使用自定义 finder/loader 对象来使用 HTTP/S 定位资源。

此外,Jossef Harushimport_cdn的答案中的函数在's和函数中几乎完全相同。httpimportgithub_repobitbucket_repo

@Marcin 的答案包含httpimport's loader 类的大部分代码。

于 2019-09-25T19:47:44.807 回答