封装导入模块的范围

时间:2016-03-09 23:10:03

标签: python class namespaces instance

在项目中使用hideous RoboClaw Python "library",我似乎无法解决这样一个事实:他们抛出了一堆函数和全局变量来处理与物理硬件连接到文件中的问题。不幸的是,我被困在使用这个库,因为当供应商为他们的主板发布新的固件时,他们也会在他们的网站上更新这个文件;将它移植到有用的东西将是一个持续的努力。

当我尝试多次导入时会出现问题,对于我连接到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文件。

对于我应该继续这样做的方向有点失落,因为我以前从来没有处理过这个问题。

1 个答案:

答案 0 :(得分:1)

通常我会谴责像我建议的那样的黑客攻击但似乎你没有多少选择,因为该程序包的作者显然不理解{{3有一种方法可以通过直接调用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.