在我的 Python 程序中,我想通过将字符串参数转换为变量名来动态加载模块和访问模块的变量。
用例
我在 SD 卡上有不同的字体,它们是 python 文件,还有一个显示功能,可以在需要显示字符时加载字体。
我的字体文件示例:
# arial14.py
# ch_(ASCII) = (widht), (height), [bitmask]
ch_33 = 3, 16, [0,0,0,0,0,0,0,0,0,1,1,1,1,1 ........
ch_34 = 5, 16, [0,0,0,0,0,0,0,0,0,0,0,0,0,0 ........
....
# arial20.py
ch_33 = 4, 22, [0,0,0,0,0,0,0,0,0,1,1,1,1,1 ........
ch_34 = 8, 22, [0,0,0,0,0,0,0,0,0,0,0,0,0,0 ........
此外,还有一个 Writer 类可以将字体呈现到显示器上:
class Writer(object):
def __init__(self):
try:
global arial14
import arial14
self.current_module = "arial14"
self.imported_fonts = []
self.imported_fonds.append(self.current_module)
except ImportError:
print("Error loading Font")
def setfont(self, fontname, fontsize):
modname = fontname+str(fontsize)
if modname not in self.importedfonts:
try:
exec("global" + modname)
exec("import" + modname) #import the font (works)
self.importedfonts.append(modname)
except ImportError:
print("Error loading Font")
return
else:
print(modname+" was already imported")
self.current_module = modname
print("Font is set now to: "+ self.current_module
## HERE COMES THE NON WORKING PART:
def putc_ascii(self, ch, xpos, ypos):
execline = "width, height, bitmap = "+ self.cur_mod+".ch_"+str(ch)
print(execline)
#this example.: width, height,bitmap = arial14.ch_55
width, height,bitmap = arial14.ch_32
print(width, height, bitmap) # values of arial14.ch_32 -> correct
exec (execline)
print(width, height, bitmap) # values of arial14.ch_32
# BUT VALUES OF arial14.ch_55 EXPECTED
有没有人知道如何将正确字体的查询字符的正确值保存到变量宽度、高度和位图中?
我只想在需要时动态加载字体,并通过将新的 .py 字体文件放入文件夹来提供添加新字体的可能性。
提前致谢。
编辑
OP实际上使用的是micropython,它没有实现importlib ...
可能的(未经测试的)解决方案(是的,使用exec
- 如果有人知道更好的解决方案,请加入)。
def import_module(name):
name = name.strip().split(
statement = "import {}"
exec(statement, globals())
return sys.modules[name]
class Writer(object):
def __init__(self):
# reference to the current module
# WARNING : this is the `module` object itself,
# not it's name
self.current_module = None
# {name:module} mapping
# not sure it's still useful since we
# now have a reference to the module itself
# and `sys.modules` already caches imported
# modules...
self.imported_fonts = {}
# set default font
self.setfont("arial", "14")
def setfont(self, fontname, fontsize):
self.current_module = self._loadfont(fontname, fontsize)
def _loadfont(self, fontname, fontsize):
name = fontname+str(fontsize)
if name not in self.imported_fonts:
self.imported_fonts[name] = load_module(name)
return self.imported_font[name]
def putc_ascii(self, ch, xpos, ypos):
width, height, bitmap = self._get_char(ch)
print("{}.{}: {} - {} - {}".format(
self.current_module, ch, width, height, bitmap
)
def _get_char(self, chrnum):
# assume the font modules have been rewritten
# using dicts (cf lower) and all chars are defined
# in all fonts modules
return self.current_module[ch]
# alternate implementation using the current
# fonts definitions
# return getattr(self.current_module, "ch_{}".format(ch))
电话:DR:
你想要importlib.import_module
,最终getattr()
。但是你仍然应该阅读更长的答案,真的,它会为你节省很多时间和挫折。
更长的答案:
关于“字体”文件格式的第一点 - 这个:
ch_33 = 3, 16, [0,0,0,0,0,0,0,0,0,1,1,1,1,1 ........
ch_34 = 5, 16, [0,0,0,0,0,0,0,0,0,0,0,0,0,0 ........
是一种巨大的设计气味。你想要列表或字典(或者可能是有序的字典),即:
characters = {
33: (3, 16, [0,0,0,0,0,0,0,0,0,1,1,1,1,1...]),
34: (5, 16, [0,0,0,0,0,0,0,0,0,0,0,0,0,0...]),
# etc
}
作为一般规则,当您开始使用“var1”、“var2”、“var3”等模式时,您就知道您想要某种容器。
第二点 - 您的错误处理,即:
try:
global arial14
import arial14
self.current_module = "arial14"
self.imported_fonts = []
self.imported_fonds.append(self.current_module)
except ImportError:
print("Error loading Font")
比无用更糟糕,它实际上是有害的。首先是因为它不会在出现不可恢复错误的情况下停止程序执行(当发生完全错误的事情时,您不希望程序继续运行),然后因为它替换了您从错误消息中获得的所有非常有用的信息和带有无用的“发生错误”消息的回溯。
仅捕获您可以通过一种或另一种方式正确管理的异常,让其他所有内容传播(也许调用堆栈中的上层人员 - 通常在 UI 部分 - 可能能够正确处理它)。
第三点:不要使用全局变量。我的意思是:不要改变或重新绑定全局变量(只读(伪常量)全局变量当然是可以的)。这意味着您真的永远不必在代码中使用“global”关键字。
当您需要在一组函数之间共享状态时,请使用类,将状态存储为属性并使您的函数成为方法。这就是对象的用途(嗯,这不仅是存在的理由之一)。
编辑:这部分对于完整的 Python 实现仍然是正确的,对于 micropython 可能仍然部分正确,除了在 micropython 中没有实现的部分(比如importlib
- 我不知道还缺少什么)
最后:永远不要使用exec
nor eval
。你不需要它们,无论你想做什么,都有一个更好、更安全的特定解决方案。
在您的情况下,要通过名称导入模块,您有importlib.import_module
,并通过您拥有的名称获取对象的属性getattr()
(但如果您使用适当的容器,请参见第一点,您甚至不需要getattr
这里)。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句