【问题标题】:Hacking python's import statement破解python的import语句
【发布时间】:2016-06-02 12:45:44
【问题描述】:

我正在为一个相当特定的目的构建一个 Python 模块。我想做的是在importing 后面获得更多功能。

我想要一个设置,通过它说from my_module import foo 将运行一个函数并传递字符串"foo"。此函数将返回应导入的对象。

例如,也许我想做一个基于云的导入系统。我想将社区脚本存储在云中,然后在用户尝试导入它们时下载它们。

也许我使用代码from cloud import test_module。这将检查缓存以确定test_module 是否已下载。如果是这样,它将返回该模块。如果没有,它会在导入之前下载模块。

我怎样才能在 Python 中完成这样的事情,通过它可以无缝地从云端imported 动态范围的子模块?

【问题讨论】:

  • 我确信有办法做到这一点,但我会要求你不要这样做。继续打开 python 终端并运行import this。第二行说什么? Explicit is better than implicit. 这对于编写好的 Python 至关重要。在没有事先咨询程序员的情况下拥有一个在后台执行各种奇怪事情的模块并不是非常 Pythonic。
  • 好的。那么,写一个像cloud.Import("test_module")这样的函数来代替内置的导入会更好吗?
  • 你在这里描述的设计模式是装饰器。 Import 在导入的模块中运行东西,但你总是得到相同的已知功能
  • 如果最好使用importlib 模块编写自定义查找器和加载器。 docs.python.org/3/library/importlib.html
  • 您描述的系统有很多问题。一方面它在没有互联网连接的情况下无法工作,调用你的库的脚本现在需要提升权限才能运行,因为它现在将被下载并将内容写入磁盘(可能让用户感到惊讶);这可能是生产服务器上的问题。像这样的系统使标准导入机制复杂化,并没有真正看到任何收益或优势。这个包每次运行时都会连接到网络吗?即使我已经 DL'ed 包裹?您将如何管理版本控制?

标签: python python-import python-module globals


【解决方案1】:

对您所要求的功能的全功能支持可能需要使用importlib 并连接到导入机制的各个部分的复杂代码。然而,一个更有限的解决方案可以只使用一个伪装成模块的自定义类来实现。

当你导入一个模块时,Python 首先检查sys.modules 字典,看看这个模块是否是一个键。如果是,则返回与键关联的值。无论值是什么,它都会这样做,因此您可以将任何类型的对象放在sys.modules 中,Python 会将其视为模块。一个模块的代码甚至可以替换它自己在sys.modules中的条目,并且即使是第一次imported也会使用替换!

因此,要实现按需下载其他模块的精美模块,请将模块本身替换为自定义类的实例,并为该类编写一个 __getattr____getattribute__ 方法来完成您想要的工作。

这是一个简单的示例模块,它为您在其中查找的任何属性返回一个字符串。该字符串将始终与请求的属性名称相同。在您的代码中,您需要执行您喜欢的网络缓存查找和下载,然后返回获取的模块对象,而不是仅仅返回一个字符串。

class FakeModule(object):
    def __getattribute__(self, name):
        return name

import sys
sys.modules[__name__] = FakeModule()

在我的系统上,我已将其保存为 fakemodule.py。现在,如果我执行from fakemodule import foo,我会在我的本地命名空间中得到foo,其值为'foo'

请注意,这仅适用于一级深度导入。如果你这样做 from fakemodule.subpackage import name 它将不起作用,因为在 sys.modules 中没有 fakemodule.subpackage 条目。

【讨论】:

  • 这太棒了,我不知道我能做到这一点。这正是我需要的,谢谢。
  • builtins.__import__ = hack_import
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-31
  • 2014-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多