python - 封装导入模块的范围

标签 python class namespaces instance

使用hideous RoboClaw Python "library"在一个项目中,我似乎无法忽视这样一个事实:他们将一堆处理与物理硬件接口(interface)的函数和全局变量放入文件中。不幸的是,我一直在使用这个库,因为当供应商为其主板发布新固件时,他们也会在其网站上更新此文件;将其移植到有用的东西将是一个持续的努力。

当我尝试多次导入它时,就会出现问题,对于我连接到 USB 的每个板一次。像这样(概念上)的东西将是理想的:

import roboclaw
class Board:
    def __init__(self):
        self.rc = roboclaw

由于Python解释器似乎在每次导入时都在内存中维护相同的模块引用,所以我似乎无法让它创建存在于单独命名空间中的实例,本质上是在所有情况下都会吐出各种I/O冲突错误板错误地分配给相同的 /dev/ttyACM 设备文件。我似乎能得到的最接近的是 this answer provided by Noctis Skytower ,但它仍然没有为每个 Board 实例创建单独的命名空间。

此外,我尝试使用 imp (如 this )和 importlib (如 this )设置动态导入,尽管这两个都无法导入,因为他们找不到位于同一目录中的 roboclaw.py 文件。

对于我应该继续做这件事的方向有点迷茫,因为我以前从未处理过这个问题。

最佳答案

好吧,通常我会谴责像我建议的那样的黑客行为,但似乎你没有太多选择,因为该包的作者显然不理解 object oriented programming 的含义,有一种方法可以通过直接调用 FunctionType() 构造函数来创建具有不同全局范围的函数的副本:

from types import FunctionType
from functools import wraps

def copy_func(func,global_namespace):
    "copies a function object with the new specified global scope"
    c = FunctionType(func.__code__,global_namespace,func.__name__,func.__defaults__,func.__closure__)
    try:
        c.__kwdefaults__ = func.__kwdefaults__
    except AttributeError:pass #this is only for python 3
    c = wraps(func)(c) #copy all metadata although there doesn't seem to be any for roboclaw
    return c

这样它根本不会影响模块中的功能,但仍然使用您自己的命名空间,然后您可以使用以下方式欺骗复制模块:

class CopyScope:
    def __init__(self,module):
        own_scope = self.__dict__
        for name,thing in vars(module).items():
            if isinstance(thing,FunctionType):
                setattr(self, name, copy_func(thing, own_scope))
            else:
                setattr(self, name, thing)
                #you could also do own_scope[name] = .. instead of setattr() but I prefer setattr()

虽然这只对所有模块级函数运行 copy_func ,而不是任何可能使用全局语句的方法,但我想如果作者了解什么方法,你就不需要这个完全没有。

我可以使用以下代码对此进行测试:

import roboclaw
x = CopyScope(roboclaw)

x.crc_clear()
x.crc_update(4)

print(x._crc)
print(roboclaw._crc) #this will actually raise an error because it isn't defined in the original module yet.

关于python - 封装导入模块的范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35904507/

相关文章:

C++ 程序返回默认值 0

java - 如何在 Java 中使用 xPath 从包含命名空间的 xml 中提取元素值?

asp.net-mvc - 无法从 Asp.Net Mvc 应用程序中找到 DataContractJsonSerializer

python - 在 virtualenv 中安装gym[atari]

python - 结合两个字典,仍然保留对 python 中原始对象的引用

python - 与列表相比,从数据框中提取字符串

c++ - 将类型导出到 python

c++ - BinaryNode 和 oldNode 未在此范围内声明

java - 从另一个类访问变量

php - Illuminate\Database\Query\Builder::labels 不存在